123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- import { LRFUExpirer, EXPIRED_ENTRY } from './LRFUExpirer.js'
- export { LRFUExpirer } from './LRFUExpirer.js'
- let defaultExpirer
- export class WeakLRUCache extends Map {
- constructor(options) {
- super()
- this.hits = 0
- this.misses = 0
- if (options && options.cacheSize) {
- options.lruSize = options.cacheSize >> 2
- }
- if (options && options.clearKeptInterval) {
- this.clearKeptInterval = options.clearKeptInterval
- this.clearKeptCount = 0
- this.clearKeptObjects = options.clearKeptObjects
- }
- this.expirer = (options ? options.expirer === false ? defaultNoLRUExpirer : options.expirer : null) || defaultExpirer || (defaultExpirer = new LRFUExpirer(options))
- this.deferRegister = Boolean(options && options.deferRegister)
- let registry = this.registry = new FinalizationRegistry(key => {
- let entry = super.get(key)
- if (entry && entry.deref && entry.deref() === undefined)
- super.delete(key)
- })
- }
- onRemove(entry) {
- let target = entry.deref && entry.deref()
- if (target) {
- // remove strong reference, so only a weak reference, wait until it is finalized to remove
- this.registry.register(target, entry.key)
- entry.value = undefined
- } else if (entry.key) {
- let currentEntry = super.get(entry.key)
- if (currentEntry === entry)
- super.delete(entry.key)
- }
- }
- get(key, mode) {
- let entry = super.get(key)
- let value
- if (entry) {
- this.hits++
- value = entry.value
- if (value === EXPIRED_ENTRY) {
- value = entry.deref && entry.deref()
- if (value === undefined)
- super.delete(key)
- else {
- entry.value = value
- if (this.clearKeptInterval)
- this.incrementClearKeptCount()
- if (mode !== 1)
- this.expirer.used(entry)
- return mode === 2 ? value : entry
- }
- }
- else {
- if (mode !== 1)
- this.expirer.used(entry)
- return mode === 2 ? value : entry
- }
- } else
- this.misses++
- }
- getValue(key) {
- return this.get(key, 2)
- }
- setValue(key, value, expirationPriority) {
- let entry
- if (value && typeof value == 'object') {
- entry = new WeakRef(value)
- if (this.clearKeptInterval)
- this.incrementClearKeptCount()
- entry.value = value
- if (this.deferRegister) {
- entry.key = key
- entry.cache = this
- } else
- this.registry.register(value, key)
- } else if (value !== undefined)
- entry = { value, key, cache: this }
- // else entry is undefined
- this.set(key, entry, expirationPriority)
- return entry
- }
- incrementClearKeptCount() {
- if (++this.clearKeptCount >= this.clearKeptInterval) {
- this.clearKeptCount = 0
- if (this.clearKeptObjects)
- this.clearKeptObjects()
- if (this.registry.cleanupSome)
- this.registry.cleanupSome()
- }
- }
- set(key, entry, expirationPriority) {
- let oldEntry = super.get(key)
- if (oldEntry)
- this.expirer.delete(oldEntry)
- return this.insert(key, entry, expirationPriority)
- }
- insert(key, entry, expirationPriority) {
- if (entry) {
- this.expirer.used(entry, expirationPriority)
- }
- return super.set(key, entry)
- }
- delete(key) {
- let oldEntry = super.get(key)
- if (oldEntry) {
- this.expirer.delete(oldEntry)
- }
- return super.delete(key)
- }
- used(entry, expirationPriority) {
- this.expirer.used(entry, expirationPriority)
- }
- clear() {
- for (let [ key, entry ] of this) {
- this.expirer.delete(entry)
- super.delete(key)
- }
- }
- }
- class NoLRUExpirer {
- used(entry) {
- if (entry.cache)
- entry.cache.onRemove(entry)
- else if (entry.deref) // if we have already registered the entry in the finalization registry, just mark it expired from the beginning
- entry.value = EXPIRED_ENTRY
- }
- delete(entry) {
- // nothing to do here, we don't have a separate cache here
- }
- }
- const defaultNoLRUExpirer = new NoLRUExpirer()
|