Cache With Time Limit
A cache where entries expire on their own — `setTimeout` does the eviction, so `get`/`count` never have to check timestamps themselves; they can just trust that an expired key has already deleted itself from the Map.
The problem
Implement `TimeLimitedCache` with `set(key, value, duration)` storing `key: value` for `duration` ms, after which the key becomes inaccessible; it returns `true` if an un-expired `key` already existed (overwriting both its value and duration), `false` otherwise. `get(key)` returns the value for an un-expired key, or `-1`. `count()` returns how many un-expired keys are currently stored.
The tricky part is re-`set`-ting an existing key: the old expiration must not fire late and delete the new value out from under it — the old timer has to be cancelled, not just left to race against a new one on the same key.
The approach
Each cache entry stores a `[value, timeoutId]` pair instead of just the raw value, so the timer that will eventually delete this exact key is always reachable from the entry itself.
`set` always schedules a fresh `setTimeout(() => this.cache.delete(key), duration)` — that's what makes an entry self-expiring, since `get`/`count` never need to know anything about elapsed time. If the key already existed, `hasKey` is captured before the entry is overwritten, and the *previous* entry's timeout is explicitly cancelled with `clearTimeout` — without that, the old timer would still fire after the first call's `duration` and delete the key even though the second `set` gave it a fresh, later expiration.
`get` and `count` stay trivial because expiration is enforced entirely by the timers: an expired key is simply a key that's no longer in the `Map`, so `get` is a plain lookup and `count` is just `this.cache.size`.
The solution
var TimeLimitedCache = function() {
this.cache = new Map();
};
/**
* @param {number} key
* @param {number} value
* @param {number} duration time until expiration in ms
* @return {boolean} if un-expired key already existed
*/
TimeLimitedCache.prototype.set = function(key, value, duration) {
const hasKey = this.cache.has(key);
const timeout = setTimeout(() => {
this.cache.delete(key);
}, duration);
if (hasKey) {
clearTimeout(this.cache.get(key)[1]);
}
this.cache.set(key, [value, timeout]);
return hasKey;
};
/**
* @param {number} key
* @return {number} value associated with key
*/
TimeLimitedCache.prototype.get = function(key) {
if (this.cache.has(key)) return this.cache.get(key)[0];
return -1;
};
/**
* @return {number} count of non-expired keys
*/
TimeLimitedCache.prototype.count = function() {
return this.cache.size;
};Time O(1)Space O(n)