2021-11-23 00:03:59 +03:00
|
|
|
import { LongSet } from './long-utils'
|
|
|
|
|
2021-04-08 12:19:38 +03:00
|
|
|
interface OneWayLinkedList<T> {
|
|
|
|
v: T
|
|
|
|
n?: OneWayLinkedList<T>
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-11-23 00:03:59 +03:00
|
|
|
* Simple class implementing LRU-like behaviour for a set,
|
|
|
|
* falling back to objects when `Set` is not available.
|
2021-04-08 12:19:38 +03:00
|
|
|
*
|
|
|
|
* Used to store recently received message IDs in {@link TelegramConnection}
|
|
|
|
*
|
|
|
|
* Uses one-way linked list internally to keep track of insertion order
|
|
|
|
*
|
|
|
|
* @internal
|
|
|
|
*/
|
2021-11-23 00:03:59 +03:00
|
|
|
export class LruSet<T> {
|
2021-04-08 12:19:38 +03:00
|
|
|
private _capacity: number
|
2021-11-23 00:03:59 +03:00
|
|
|
private _first?: OneWayLinkedList<T>
|
|
|
|
private _last?: OneWayLinkedList<T>
|
2021-04-08 12:19:38 +03:00
|
|
|
|
2021-11-23 00:03:59 +03:00
|
|
|
private _set?: Set<T> | LongSet
|
|
|
|
private _obj?: any
|
2021-04-08 12:19:38 +03:00
|
|
|
private _objSize?: number
|
|
|
|
|
2021-11-23 00:03:59 +03:00
|
|
|
constructor(capacity: number, useObject = false, forLong = false) {
|
2021-04-08 12:19:38 +03:00
|
|
|
this._capacity = capacity
|
|
|
|
|
2021-11-23 00:03:59 +03:00
|
|
|
if (!forLong && (typeof Set === 'undefined' || useObject)) {
|
|
|
|
this._obj = Object.create(null)
|
2021-04-08 12:19:38 +03:00
|
|
|
this._objSize = 0
|
|
|
|
this.add = this._addForObj.bind(this)
|
|
|
|
this.has = this._hasForObj.bind(this)
|
2021-11-23 00:03:59 +03:00
|
|
|
this.clear = this._clearForObj.bind(this)
|
2021-04-08 12:19:38 +03:00
|
|
|
} else {
|
2021-11-23 00:03:59 +03:00
|
|
|
this._set = forLong ? new LongSet(useObject) : new Set()
|
2021-04-08 12:19:38 +03:00
|
|
|
this.add = this._addForSet.bind(this)
|
|
|
|
this.has = this._hasForSet.bind(this)
|
2021-11-23 00:03:59 +03:00
|
|
|
this.clear = this._clearForSet.bind(this)
|
2021-04-08 12:19:38 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-23 00:03:59 +03:00
|
|
|
readonly add: (val: T) => void
|
|
|
|
readonly has: (val: T) => boolean
|
|
|
|
readonly clear: () => void
|
|
|
|
|
|
|
|
private _clearForSet() {
|
|
|
|
this._first = this._last = undefined
|
|
|
|
this._set!.clear()
|
|
|
|
}
|
|
|
|
|
|
|
|
private _clearForObj() {
|
|
|
|
this._first = this._last = undefined
|
|
|
|
this._obj = {}
|
|
|
|
this._objSize = 0
|
|
|
|
}
|
2021-04-08 12:19:38 +03:00
|
|
|
|
2021-11-23 00:03:59 +03:00
|
|
|
private _addForSet(val: T) {
|
|
|
|
if (this._set!.has(val as any)) return
|
2021-04-08 12:19:38 +03:00
|
|
|
|
2021-11-23 00:03:59 +03:00
|
|
|
if (!this._first) this._first = { v: val }
|
2021-04-08 12:19:38 +03:00
|
|
|
if (!this._last) this._last = this._first
|
|
|
|
else {
|
2021-11-23 00:03:59 +03:00
|
|
|
this._last.n = { v: val }
|
2021-04-08 12:19:38 +03:00
|
|
|
this._last = this._last.n
|
|
|
|
}
|
|
|
|
|
2021-11-23 00:03:59 +03:00
|
|
|
this._set!.add(val as any)
|
2021-04-08 12:19:38 +03:00
|
|
|
|
|
|
|
if (this._set!.size > this._capacity && this._first) {
|
|
|
|
// remove least recently used
|
2021-11-23 00:03:59 +03:00
|
|
|
this._set!.delete(this._first.v as any)
|
2021-04-08 12:19:38 +03:00
|
|
|
this._first = this._first.n
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-23 00:03:59 +03:00
|
|
|
private _hasForSet(val: T) {
|
|
|
|
return this._set!.has(val as any)
|
2021-04-08 12:19:38 +03:00
|
|
|
}
|
|
|
|
|
2021-11-23 00:03:59 +03:00
|
|
|
private _addForObj(val: T) {
|
|
|
|
if (val in this._obj!) return
|
2021-04-08 12:19:38 +03:00
|
|
|
|
2021-11-23 00:03:59 +03:00
|
|
|
if (!this._first) this._first = { v: val }
|
2021-04-08 12:19:38 +03:00
|
|
|
if (!this._last) this._last = this._first
|
|
|
|
else {
|
2021-11-23 00:03:59 +03:00
|
|
|
this._last.n = { v: val }
|
2021-04-08 12:19:38 +03:00
|
|
|
this._last = this._last.n
|
|
|
|
}
|
|
|
|
|
2021-11-23 00:03:59 +03:00
|
|
|
this._obj![val] = true
|
2021-04-08 12:19:38 +03:00
|
|
|
|
|
|
|
if (this._objSize === this._capacity) {
|
|
|
|
// remove least recently used
|
|
|
|
delete this._obj![this._first.v]
|
|
|
|
this._first = this._first.n
|
|
|
|
} else {
|
|
|
|
this._objSize! += 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-23 00:03:59 +03:00
|
|
|
private _hasForObj(val: T) {
|
|
|
|
return val in this._obj!
|
2021-04-08 12:19:38 +03:00
|
|
|
}
|
|
|
|
}
|