feat(collections): add new collection APIs, iterator support, and tree serialization utilities

This commit is contained in:
2026-03-22 08:44:49 +00:00
parent 20182a00f8
commit f4db131ede
23 changed files with 2251 additions and 2657 deletions

View File

@@ -31,6 +31,7 @@ export interface IObjectMapEventData<T> {
*/
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>>();
@@ -42,12 +43,20 @@ export class ObjectMap<T> {
// 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);
}
/**
@@ -65,6 +74,7 @@ export class ObjectMap<T> {
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,
@@ -75,19 +85,14 @@ export class ObjectMap<T> {
/**
* add object to Objectmap
* returns false if the object is already in the map
* returns true if the object was added successfully
* returns the key for the object (existing or new)
*/
public add(objectArg: T): string {
// lets search for an existing unique key
for (const keyArg of this.fastMap.getKeys()) {
const object = this.fastMap.getByKey(keyArg);
if (object === objectArg) {
return keyArg;
}
const existingKey = this.reverseMap.get(objectArg);
if (existingKey !== undefined) {
return existingKey;
}
// otherwise lets create it
const uniqueKey = uni('key');
this.addMappedUnique(uniqueKey, objectArg);
this.eventSubject.next({
@@ -110,23 +115,14 @@ export class ObjectMap<T> {
* check if object is in Objectmap
*/
public checkForObject(objectArg: T): boolean {
return !!this.getKeyForObject(objectArg);
return this.reverseMap.has(objectArg);
}
/**
* get key for object
* @param findFunction
*/
public getKeyForObject(objectArg: T) {
let foundKey: string = null;
for (const keyArg of this.fastMap.getKeys()) {
if (!foundKey && this.fastMap.getByKey(keyArg) === objectArg) {
foundKey = keyArg;
} else {
continue;
}
}
return foundKey;
public getKeyForObject(objectArg: T): string | null {
return this.reverseMap.get(objectArg) ?? null;
}
/**
@@ -181,6 +177,7 @@ export class ObjectMap<T> {
} else {
const keyToUse = keys[0];
const removedItem = this.fastMap.removeFromMap(keyToUse);
this.reverseMap.delete(removedItem);
this.eventSubject.next({
operation: 'remove',
payload: removedItem,
@@ -193,27 +190,24 @@ export class ObjectMap<T> {
* returns a cloned array of all the objects currently in the Objectmap
*/
public getArray(): T[] {
const returnArray: any[] = [];
for (const keyArg of this.fastMap.getKeys()) {
returnArray.push(this.fastMap.getByKey(keyArg));
}
return returnArray;
return this.fastMap.values();
}
/**
* check if Objectmap ist empty
*/
public isEmpty(): boolean {
return this.fastMap.getKeys().length === 0;
return this.fastMap.size === 0;
}
/**
* remove object from Objectmap
*/
public remove(objectArg: T): T {
if (this.checkForObject(objectArg)) {
const keyArg = this.getKeyForObject(objectArg);
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,
@@ -230,6 +224,7 @@ export class ObjectMap<T> {
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,
@@ -244,6 +239,10 @@ export class 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;
}
@@ -254,6 +253,26 @@ export class ObjectMap<T> {
*/
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]();
}
/**
@@ -261,6 +280,7 @@ export class ObjectMap<T> {
*/
public destroy() {
this.wipe();
this.reverseMap.clear();
this.eventSubject.complete();
}
}