Son CV dans un terminal web en Javascript! https://terminal-cv.gregandev.fr
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

119 lines
3.2 KiB

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
}
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 (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)
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
}
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 = this.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()