Skip to content

All tasks completed #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions JavaScript/.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
declare class TimeoutCollection<K, V> {
constructor(timeout: number);

set(key: K, value: V): this;
get(key: K): V | undefined;
has(key: K): boolean;
delete(key: K): boolean;
clear(): void;
size(): number;
toArray(): [K, V][];
forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void;
keys(): IterableIterator<K>;
values(): IterableIterator<V>;
entries(): IterableIterator<[K, V]>;
[Symbol.iterator](): IterableIterator<[K, V]>;

private collection: Map<K, V>;
private timers: Map<K, NodeJS.Timeout | number>;
private timeout: number;
}

export = TimeoutCollection;
116 changes: 77 additions & 39 deletions JavaScript/1-prototype.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,55 +3,93 @@
// Facade that wraps Map and Node.js Timers to provide a simple interface for a
// collection with values that have expiration timeout.

const TimeoutCollection = function (timeout) {
this.timeout = timeout;
this.collection = new Map();
this.timers = new Map();
};

TimeoutCollection.prototype.set = function (key, value) {
const timer = this.timers.get(key);
if (timer) clearTimeout(timer);
const timeout = setTimeout(() => {
class TimeoutCollection {
constructor(timeout) {
this.timeout = timeout;
this.collection = new Map();
this.timers = new Map();
this.isNode = typeof process !== 'undefined' && process.versions?.node;
}

set(key, value) {
this.delete(key);
}, this.timeout);
timeout.unref();
this.collection.set(key, value);
this.timers.set(key, timeout);
};

TimeoutCollection.prototype.get = function (key) {
return this.collection.get(key);
};
const timeoutId = setTimeout(() => {
this.delete(key);
}, this.timeout);

if (this.isNode && typeof timeoutId.unref === 'function') {
timeoutId.unref();
}

TimeoutCollection.prototype.delete = function (key) {
const timer = this.timers.get(key);
if (timer) {
clearTimeout(timer);
this.collection.delete(key);
this.timers.delete(key);
this.collection.set(key, value);
this.timers.set(key, timeoutId);
}
};

TimeoutCollection.prototype.toArray = function () {
return [...this.collection.entries()];
};
get(key) {
return this.collection.get(key);
}

// Usage
delete(key) {
const timer = this.timers.get(key);
if (timer) {
clearTimeout(timer);
this.timers.delete(key);
this.collection.delete(key);
return true;
}
return false;
}

clear() {
for (const timer of this.timers.values()) {
clearTimeout(timer);
}
this.timers.clear();
this.collection.clear();
}

has(key) {
return this.collection.has(key);
}

const hash = new TimeoutCollection(1000);
hash.set('uno', 1);
console.dir({ array: hash.toArray() });
size() {
return this.collection.size;
}

toArray() {
return [...this.collection.entries()];
}

destroy() {
this.clear();
}
}

hash.set('due', 2);
console.dir({ array: hash.toArray() });
if (typeof module !== 'undefined' && module.exports) {
module.exports = TimeoutCollection;
} else {
window.TimeoutCollection = TimeoutCollection;
}

setTimeout(() => {
hash.set('tre', 3);
// Usage

if (typeof process !== 'undefined' && process.versions?.node) {
const hash = new TimeoutCollection(1000);
hash.set('uno', 1);
console.dir({ array: hash.toArray() });

hash.set('due', 2);
console.dir({ array: hash.toArray() });

setTimeout(() => {
hash.set('quattro', 4);
hash.set('tre', 3);
console.dir({ array: hash.toArray() });
}, 500);
}, 1500);

setTimeout(() => {
hash.set('quattro', 4);
console.dir({ array: hash.toArray() });
hash.destroy();
}, 500);
}, 1500);
}
43 changes: 40 additions & 3 deletions JavaScript/2-class.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,68 @@ class TimeoutCollection {
const timeout = setTimeout(() => {
this.delete(key);
}, this.timeout);
timeout.unref();
if (typeof timeout.unref === 'function') timeout.unref();
this.collection.set(key, value);
this.timers.set(key, timeout);
return this;
}

get(key) {
return this.collection.get(key);
}

has(key) {
return this.collection.has(key);
}

delete(key) {
const timer = this.timers.get(key);
if (timer) {
clearTimeout(timer);
this.collection.delete(key);
this.timers.delete(key);
return this.collection.delete(key);
}
return false;
}

clear() {
for (const timer of this.timers.values()) {
clearTimeout(timer);
}
this.timers.clear();
this.collection.clear();
}

size() {
return this.collection.size;
}

toArray() {
return [...this.collection.entries()];
}

forEach(callbackfn, thisArg) {
return this.collection.forEach(callbackfn, thisArg);
}

keys() {
return this.collection.keys();
}

values() {
return this.collection.values();
}

entries() {
return this.collection.entries();
}

[Symbol.iterator]() {
return this.collection[Symbol.iterator]();
}
}

// Usage

const hash = new TimeoutCollection(1000);
hash.set('uno', 1);
console.dir({ array: hash.toArray() });
Expand Down
56 changes: 29 additions & 27 deletions JavaScript/3-function.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,40 @@

const timeoutCollection = (interval) => {
const collection = new Map();
const timers = new Map();

const instance = {};

instance.set = (key, value) => {
const timer = timers.get(key);
if (timer) clearTimeout(timer);
const timeout = setTimeout(() => {
const expirations = new Map();

return {
set(key, value) {
const expiration = Date.now() + interval;
collection.set(key, value);
expirations.set(key, expiration);
return this;
},
get(key) {
this.cleanup();
return collection.get(key);
},
delete(key) {
collection.delete(key);
}, interval);
timeout.unref();
collection.set(key, value);
timers.set(key, timer);
};

instance.get = (key) => collection.get(key);

instance.delete = (key) => {
const timer = timers.get(key);
if (timer) {
clearTimeout(timer);
collection.delete(key);
timers.delete(key);
expirations.delete(key);
},
toArray() {
this.cleanup();
return [...collection.entries()];
},
cleanup() {
const now = Date.now();
for (const [key, expiration] of expirations.entries()) {
if (now >= expiration) {
collection.delete(key);
expirations.delete(key);
}
}
}
};

instance.toArray = () => [...collection.entries()];

return instance;
};

// Usage

const hash = timeoutCollection(1000);
hash.set('uno', 1);
console.dir({ array: hash.toArray() });
Expand All @@ -49,5 +50,6 @@ setTimeout(() => {
setTimeout(() => {
hash.set('quattro', 4);
console.dir({ array: hash.toArray() });
hash.cleanup(); // Manually trigger cleanup
}, 500);
}, 1500);
Loading