UNPKG

@push.rocks/lik

Version:

Provides a collection of lightweight helpers and utilities for Node.js projects.

287 lines (253 loc) 7.05 kB
import * as plugins from './classes.plugins.js'; import { FastMap } from './classes.fastmap.js'; export const uni = (prefix: string = 'uni') => { return `${prefix}xxxxxxxxxxx`.replace(/[xy]/g, (c) => { const r = (Math.random() * 16) | 0; const v = c === 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); }; export interface IObjectmapForEachFunction<T> { (itemArg: T): void; } export interface IObjectmapFindFunctionSync<T> { (itemArg: T): boolean; } export interface IObjectmapFindFunction<T> { (itemArg: T): Promise<boolean>; } export interface IObjectMapEventData<T> { operation: 'add' | 'remove'; payload: T; } /** * allows keeping track of objects */ export class ObjectMap<T> { private fastMap = new FastMap<T>(); private reverseMap = new Map<T, string>(); // events public eventSubject = new plugins.smartrx.rxjs.Subject<IObjectMapEventData<T>>(); /** * returns a new instance */ constructor() { // nothing here } /** * the number of objects in the map */ public get length(): number { return this.fastMap.size; } /** * adds an object mapped to a string * the string must be unique */ addMappedUnique(uniqueKeyArg: string, objectArg: T) { this.fastMap.addToMap(uniqueKeyArg, objectArg); this.reverseMap.set(objectArg, uniqueKeyArg); } /** * fastest way to get an object from the map * @param uniqueKey */ public getMappedUnique(uniqueKeyArg: string) { return this.fastMap.getByKey(uniqueKeyArg); } /** * remove key * @param functionArg */ public removeMappedUnique(uniqueKey: string): T { const object = this.fastMap.removeFromMap(uniqueKey); if (object !== undefined) { this.reverseMap.delete(object); this.eventSubject.next({ operation: 'remove', payload: object, }); } return object; } /** * add object to Objectmap * returns the key for the object (existing or new) */ public add(objectArg: T): string { const existingKey = this.reverseMap.get(objectArg); if (existingKey !== undefined) { return existingKey; } const uniqueKey = uni('key'); this.addMappedUnique(uniqueKey, objectArg); this.eventSubject.next({ operation: 'add', payload: objectArg, }); return uniqueKey; } /** * like .add but adds an whole array of objects */ public addArray(objectArrayArg: T[]) { for (const item of objectArrayArg) { this.add(item); } } /** * check if object is in Objectmap */ public checkForObject(objectArg: T): boolean { return this.reverseMap.has(objectArg); } /** * get key for object */ public getKeyForObject(objectArg: T): string | null { return this.reverseMap.get(objectArg) ?? null; } /** * find object */ public async find(findFunction: IObjectmapFindFunction<T>): Promise<T> { return this.fastMap.find(findFunction); } public findSync(findFunction: IObjectmapFindFunctionSync<T>): T { for (const keyArg of this.fastMap.getKeys()) { if (findFunction(this.fastMap.getByKey(keyArg))) { return this.getMappedUnique(keyArg); } } } /** * finds a specific element and then removes it */ public async findOneAndRemove(findFunction: IObjectmapFindFunction<T>): Promise<T> { const foundElement = await this.find(findFunction); if (foundElement) { this.remove(foundElement); } return foundElement; } public findOneAndRemoveSync(findFunction: IObjectmapFindFunctionSync<T>): T { const foundElement = this.findSync(findFunction); if (foundElement) { this.remove(foundElement); } return foundElement; } /** * run function for each item in Objectmap */ public async forEach(functionArg: IObjectmapForEachFunction<T>) { for (const keyArg of this.fastMap.getKeys()) { await functionArg(this.fastMap.getByKey(keyArg)); } } /** * gets an object in the Observablemap and removes it, so it can't be retrieved again */ public getOneAndRemove(): T { const keys = this.fastMap.getKeys(); if (keys.length === 0) { return null; } else { const keyToUse = keys[0]; const removedItem = this.fastMap.removeFromMap(keyToUse); this.reverseMap.delete(removedItem); this.eventSubject.next({ operation: 'remove', payload: removedItem, }); return removedItem; } } /** * returns a cloned array of all the objects currently in the Objectmap */ public getArray(): T[] { return this.fastMap.values(); } /** * check if Objectmap ist empty */ public isEmpty(): boolean { return this.fastMap.size === 0; } /** * remove object from Objectmap */ public remove(objectArg: T): T { const keyArg = this.reverseMap.get(objectArg); if (keyArg !== undefined) { const removedObject = this.fastMap.removeFromMap(keyArg); this.reverseMap.delete(removedObject); this.eventSubject.next({ operation: 'remove', payload: removedObject, }); return removedObject; } return null; } /** * wipe Objectmap */ public wipe() { const keys = this.fastMap.getKeys(); for (const keyArg of keys) { const removedObject = this.fastMap.removeFromMap(keyArg); this.reverseMap.delete(removedObject); this.eventSubject.next({ operation: 'remove', payload: removedObject, }); } } /** * returns a new Objectmap that includes */ public concat(objectMapArg: ObjectMap<T>) { const concattedObjectMap = new ObjectMap<T>(); concattedObjectMap.fastMap.addAllFromOther(this.fastMap); concattedObjectMap.fastMap.addAllFromOther(objectMapArg.fastMap); // rebuild reverse map for the concatenated map for (const key of concattedObjectMap.fastMap.getKeys()) { concattedObjectMap.reverseMap.set(concattedObjectMap.fastMap.getByKey(key), key); } return concattedObjectMap; } /** * tries to merge another Objectmap * Note: uniqueKeyCollisions will cause overwrite * @param objectMapArg */ public addAllFromOther(objectMapArg: ObjectMap<T>) { this.fastMap.addAllFromOther(objectMapArg.fastMap); // rebuild reverse map for (const key of objectMapArg.fastMap.getKeys()) { this.reverseMap.set(objectMapArg.fastMap.getByKey(key), key); } } public map<U>(fn: (item: T) => U): U[] { return this.getArray().map(fn); } public filter(fn: (item: T) => boolean): T[] { return this.getArray().filter(fn); } public reduce<U>(fn: (acc: U, item: T) => U, initial: U): U { return this.getArray().reduce(fn, initial); } public [Symbol.iterator](): Iterator<T> { return this.getArray()[Symbol.iterator](); } /** * destroys the ObjectMap, completing the eventSubject and clearing all entries */ public destroy() { this.wipe(); this.reverseMap.clear(); this.eventSubject.complete(); } }