AK-21/Graphite-Industrial-Intelligence
0
1'use strict';2 3class QuickLRU {4 constructor(options = {}) {5 if (!(options.maxSize && options.maxSize > 0)) {6 throw new TypeError('`maxSize` must be a number greater than 0');7 }8 9 if (typeof options.maxAge === 'number' && options.maxAge === 0) {10 throw new TypeError('`maxAge` must be a number greater than 0');11 }12 13 this.maxSize = options.maxSize;14 this.maxAge = options.maxAge || Infinity;15 this.onEviction = options.onEviction;16 this.cache = new Map();17 this.oldCache = new Map();18 this._size = 0;19 }20 21 _emitEvictions(cache) {22 if (typeof this.onEviction !== 'function') {23 return;24 }25 26 for (const [key, item] of cache) {27 this.onEviction(key, item.value);28 }29 }30 31 _deleteIfExpired(key, item) {32 if (typeof item.expiry === 'number' && item.expiry <= Date.now()) {33 if (typeof this.onEviction === 'function') {34 this.onEviction(key, item.value);35 }36 37 return this.delete(key);38 }39 40 return false;41 }42 43 _getOrDeleteIfExpired(key, item) {44 const deleted = this._deleteIfExpired(key, item);45 if (deleted === false) {46 return item.value;47 }48 }49 50 _getItemValue(key, item) {51 return item.expiry ? this._getOrDeleteIfExpired(key, item) : item.value;52 }53 54 _peek(key, cache) {55 const item = cache.get(key);56 57 return this._getItemValue(key, item);58 }59 60 _set(key, value) {61 this.cache.set(key, value);62 this._size++;63 64 if (this._size >= this.maxSize) {65 this._size = 0;66 this._emitEvictions(this.oldCache);67 this.oldCache = this.cache;68 this.cache = new Map();69 }70 }71 72 _moveToRecent(key, item) {73 this.oldCache.delete(key);74 this._set(key, item);75 }76 77 * _entriesAscending() {78 for (const item of this.oldCache) {79 const [key, value] = item;80 if (!this.cache.has(key)) {81 const deleted = this._deleteIfExpired(key, value);82 if (deleted === false) {83 yield item;84 }85 }86 }87 88 for (const item of this.cache) {89 const [key, value] = item;90 const deleted = this._deleteIfExpired(key, value);91 if (deleted === false) {92 yield item;93 }94 }95 }96 97 get(key) {98 if (this.cache.has(key)) {99 const item = this.cache.get(key);100 101 return this._getItemValue(key, item);102 }103 104 if (this.oldCache.has(key)) {105 const item = this.oldCache.get(key);106 if (this._deleteIfExpired(key, item) === false) {107 this._moveToRecent(key, item);108 return item.value;109 }110 }111 }112 113 set(key, value, {maxAge = this.maxAge === Infinity ? undefined : Date.now() + this.maxAge} = {}) {114 if (this.cache.has(key)) {115 this.cache.set(key, {116 value,117 maxAge118 });119 } else {120 this._set(key, {value, expiry: maxAge});121 }122 }123 124 has(key) {125 if (this.cache.has(key)) {126 return !this._deleteIfExpired(key, this.cache.get(key));127 }128 129 if (this.oldCache.has(key)) {130 return !this._deleteIfExpired(key, this.oldCache.get(key));131 }132 133 return false;134 }135 136 peek(key) {137 if (this.cache.has(key)) {138 return this._peek(key, this.cache);139 }140 141 if (this.oldCache.has(key)) {142 return this._peek(key, this.oldCache);143 }144 }145 146 delete(key) {147 const deleted = this.cache.delete(key);148 if (deleted) {149 this._size--;150 }151 152 return this.oldCache.delete(key) || deleted;153 }154 155 clear() {156 this.cache.clear();157 this.oldCache.clear();158 this._size = 0;159 }160 161 resize(newSize) {162 if (!(newSize && newSize > 0)) {163 throw new TypeError('`maxSize` must be a number greater than 0');164 }165 166 const items = [...this._entriesAscending()];167 const removeCount = items.length - newSize;168 if (removeCount < 0) {169 this.cache = new Map(items);170 this.oldCache = new Map();171 this._size = items.length;172 } else {173 if (removeCount > 0) {174 this._emitEvictions(items.slice(0, removeCount));175 }176 177 this.oldCache = new Map(items.slice(removeCount));178 this.cache = new Map();179 this._size = 0;180 }181 182 this.maxSize = newSize;183 }184 185 * keys() {186 for (const [key] of this) {187 yield key;188 }189 }190 191 * values() {192 for (const [, value] of this) {193 yield value;194 }195 }196 197 * [Symbol.iterator]() {198 for (const item of this.cache) {199 const [key, value] = item;200 const deleted = this._deleteIfExpired(key, value);201 if (deleted === false) {202 yield [key, value.value];203 }204 }205 206 for (const item of this.oldCache) {207 const [key, value] = item;208 if (!this.cache.has(key)) {209 const deleted = this._deleteIfExpired(key, value);210 if (deleted === false) {211 yield [key, value.value];212 }213 }214 }215 }216 217 * entriesDescending() {218 let items = [...this.cache];219 for (let i = items.length - 1; i >= 0; --i) {220 const item = items[i];221 const [key, value] = item;222 const deleted = this._deleteIfExpired(key, value);223 if (deleted === false) {224 yield [key, value.value];225 }226 }227 228 items = [...this.oldCache];229 for (let i = items.length - 1; i >= 0; --i) {230 const item = items[i];231 const [key, value] = item;232 if (!this.cache.has(key)) {233 const deleted = this._deleteIfExpired(key, value);234 if (deleted === false) {235 yield [key, value.value];236 }237 }238 }239 }240 241 * entriesAscending() {242 for (const [key, value] of this._entriesAscending()) {243 yield [key, value.value];244 }245 }246 247 get size() {248 if (!this._size) {249 return this.oldCache.size;250 }251 252 let oldCacheSize = 0;253 for (const key of this.oldCache.keys()) {254 if (!this.cache.has(key)) {255 oldCacheSize++;256 }257 }258 259 return Math.min(this._size + oldCacheSize, this.maxSize);260 }261}262 263module.exports = QuickLRU;264 