Replace Map with Collection

This commit is contained in:
Androz2091
2020-05-26 16:00:31 +02:00
parent f43c348b6c
commit e87dff66ac
3 changed files with 254 additions and 13 deletions

View File

@@ -1,3 +1,4 @@
import Collection from "../utils/collection.ts";
import { identifyPayload } from "../module/client.ts";
import { endpoints } from "../constants/discord.ts";
import { formatImageURL } from "../utils/cdn.ts";
@@ -66,21 +67,21 @@ export const createGuild = (data: CreateGuildPayload, shardID: number) => {
preferredLocale: data.preferred_locale,
/** The roles in the guild */
roles: new Map(data.roles.map((r) => [r.id, createRole(r)])),
roles: new Collection(data.roles.map((r) => [r.id, createRole(r)])),
/** When this guild was joined at. */
joinedAt: Date.parse(data.joined_at),
/** The users in this guild. */
members: new Map<string, Member>(),
members: new Collection<string, Member>(),
/** The channels in the guild */
channels: new Map(
channels: new Collection(
data.channels.map((c) => [c.id, createChannel(c, data.id)]),
),
/** The presences of all the users in the guild. */
presences: new Map(data.presences.map((p) => [p.user.id, p])),
presences: new Collection(data.presences.map((p) => [p.user.id, p])),
/** The total number of members in this guild. This value is updated as members leave and join the server. However, if you do not have the intent enabled to be able to listen to these events, then this will not be accurate. */
memberCount: data.member_count || 0,
/** The Voice State data for each user in a voice channel in this server. */
voiceStates: new Map(data.voice_states.map((vs) => [vs.user_id, {
voiceStates: new Collection(data.voice_states.map((vs) => [vs.user_id, {
...vs,
guildID: vs.guild_id,
channelID: vs.channel_id,

View File

@@ -1,17 +1,18 @@
import Collection from "./collection.ts";
import { Message } from "../structures/message.ts";
import { Guild } from "../structures/guild.ts";
import { Channel } from "../structures/channel.ts";
export interface CacheData {
guilds: Map<string, Guild>;
channels: Map<string, Channel>;
messages: Map<string, Message>;
unavailableGuilds: Map<string, number>;
guilds: Collection<string, Guild>;
channels: Collection<string, Channel>;
messages: Collection<string, Message>;
unavailableGuilds: Collection<string, number>;
}
export const cache: CacheData = {
guilds: new Map(),
channels: new Map(),
messages: new Map(),
unavailableGuilds: new Map(),
guilds: new Collection(),
channels: new Collection(),
messages: new Collection(),
unavailableGuilds: new Collection(),
};

239
utils/collection.ts Normal file
View File

@@ -0,0 +1,239 @@
class Collection<K, V> extends Map<K, V> {
private _array!: V[] | null;
public static readonly default: typeof Collection = Collection;
public ["constructor"]: typeof Collection;
public constructor(entries?: ReadonlyArray<readonly [K, V]> | null) {
super(entries);
Object.defineProperty(
this,
"_array",
{ value: null, writable: true, configurable: true },
);
Object.defineProperty(
this,
"_keyArray",
{ value: null, writable: true, configurable: true },
);
}
public get(key: K): V | undefined {
return super.get(key);
}
public set(key: K, value: V): this {
this._array = null;
return super.set(key, value);
}
public has(key: K): boolean {
return super.has(key);
}
public delete(key: K): boolean {
this._array = null;
return super.delete(key);
}
public clear(): void {
return super.clear();
}
public array(): V[] {
if (!this._array || this._array.length !== this.size) {
this._array = [...this.values()];
}
return this._array;
}
public first(): V | undefined;
public first(amount: number): V[];
public first(amount?: number): V | V[] | undefined {
if (typeof amount === "undefined") return this.values().next().value;
if (amount < 0) return this.last(amount * -1);
amount = Math.min(this.size, amount);
const iter = this.values();
return Array.from({ length: amount }, (): V => iter.next().value);
}
public last(): V | undefined;
public last(amount: number): V[];
public last(amount?: number): V | V[] | undefined {
const arr = this.array();
if (typeof amount === "undefined") return arr[arr.length - 1];
if (amount < 0) return this.first(amount * -1);
if (!amount) return [];
return arr.slice(-amount);
}
public random(): V;
public random(amount: number): V[];
public random(amount?: number): V | V[] {
let arr = this.array();
if (
typeof amount === "undefined"
) {
return arr[Math.floor(Math.random() * arr.length)];
}
if (arr.length === 0 || !amount) return [];
arr = arr.slice();
return Array.from(
{ length: amount },
(): V => arr.splice(Math.floor(Math.random() * arr.length), 1)[0],
);
}
public find(
fn: (value: V, key: K, collection: this) => boolean,
): V | undefined;
public find<T>(
fn: (this: T, value: V, key: K, collection: this) => boolean,
thisArg: T,
): V | undefined;
public find(
fn: (value: V, key: K, collection: this) => boolean,
thisArg?: unknown,
): V | undefined {
if (typeof thisArg !== "undefined") fn = fn.bind(thisArg);
for (const [key, val] of this) {
if (fn(val, key, this)) return val;
}
return undefined;
}
public filter(fn: (value: V, key: K, collection: this) => boolean): this;
public filter<T>(
fn: (this: T, value: V, key: K, collection: this) => boolean,
thisArg: T,
): this;
public filter(
fn: (value: V, key: K, collection: this) => boolean,
thisArg?: unknown,
): this {
if (typeof thisArg !== "undefined") fn = fn.bind(thisArg);
const results = new this.constructor[Symbol.species]<K, V>() as this;
for (const [key, val] of this) {
if (fn(val, key, this)) results.set(key, val);
}
return results;
}
public map<T>(fn: (value: V, key: K, collection: this) => T): T[];
public map<This, T>(
fn: (this: This, value: V, key: K, collection: this) => T,
thisArg: This,
): T[];
public map<T>(
fn: (value: V, key: K, collection: this) => T,
thisArg?: unknown,
): T[] {
if (typeof thisArg !== "undefined") fn = fn.bind(thisArg);
const iter = this.entries();
return Array.from({ length: this.size }, (): T => {
const [key, value] = iter.next().value;
return fn(value, key, this);
});
}
public some(fn: (value: V, key: K, collection: this) => boolean): boolean;
public some<T>(
fn: (this: T, value: V, key: K, collection: this) => boolean,
thisArg: T,
): boolean;
public some(
fn: (value: V, key: K, collection: this) => boolean,
thisArg?: unknown,
): boolean {
if (typeof thisArg !== "undefined") fn = fn.bind(thisArg);
for (const [key, val] of this) {
if (fn(val, key, this)) return true;
}
return false;
}
public every(fn: (value: V, key: K, collection: this) => boolean): boolean;
public every<T>(
fn: (this: T, value: V, key: K, collection: this) => boolean,
thisArg: T,
): boolean;
public every(
fn: (value: V, key: K, collection: this) => boolean,
thisArg?: unknown,
): boolean {
if (typeof thisArg !== "undefined") fn = fn.bind(thisArg);
for (const [key, val] of this) {
if (!fn(val, key, this)) return false;
}
return true;
}
public reduce<T>(
fn: (accumulator: T, value: V, key: K, collection: this) => T,
initialValue?: T,
): T {
let accumulator!: T;
if (typeof initialValue !== "undefined") {
accumulator = initialValue;
for (const [key, val] of this) {
accumulator = fn(accumulator, val, key, this);
}
return accumulator;
}
let first = true;
for (const [key, val] of this) {
if (first) {
accumulator = val as unknown as T;
first = false;
continue;
}
accumulator = fn(accumulator, val, key, this);
}
// No items iterated.
if (first) {
throw new TypeError("Reduce of empty collection with no initial value");
}
return accumulator;
}
public each(fn: (value: V, key: K, collection: this) => void): this;
public each<T>(
fn: (this: T, value: V, key: K, collection: this) => void,
thisArg: T,
): this;
public each(
fn: (value: V, key: K, collection: this) => void,
thisArg?: unknown,
): this {
this.forEach(fn as (value: V, key: K, map: Map<K, V>) => void, thisArg);
return this;
}
public sort(
compareFunction: (
firstValue: V,
secondValue: V,
firstKey: K,
secondKey: K,
) => number = (x, y): number => Number(x > y) || Number(x === y) - 1,
): this {
const entries = [...this.entries()];
entries.sort((a, b): number => compareFunction(a[1], b[1], a[0], b[0]));
// Perform clean-up
super.clear();
this._array = null;
// Set the new entries
for (const [k, v] of entries) {
super.set(k, v);
}
return this;
}
}
export default Collection;