deque-typed
Version:
429 lines (428 loc) • 15.5 kB
TypeScript
/**
* data-structure-typed
*
* @author Pablo Zeng
* @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import type { EntryCallback, HashMapLinkedNode, HashMapOptions, HashMapStoreItem, LinkedHashMapOptions } from '../../types';
import { IterableEntryBase } from '../base';
/**
* Hash-based map. Supports object keys and custom hashing; offers O(1) average set/get/has.
* @remarks Time O(1), Space O(1)
* @template K
* @template V
* @template R
* 1. Key-Value Pair Storage: HashMap stores key-value pairs. Each key map to a value.
* 2. Fast Lookup: It's used when you need to quickly find, insert, or delete entries based on a key.
* 3. Unique Keys: Keys are unique.
* If you try to insert another entry with the same key, the new one will replace the old entry.
* 4. Unordered Collection: HashMap does not guarantee the order of entries, and the order may change over time.
* @example
* // should maintain insertion order
* const linkedHashMap = new LinkedHashMap<number, string>();
* linkedHashMap.set(1, 'A');
* linkedHashMap.set(2, 'B');
* linkedHashMap.set(3, 'C');
*
* const result = Array.from(linkedHashMap);
* console.log(result); // [
* // [1, 'A'],
* // [2, 'B'],
* // [3, 'C']
* // ];
* @example
* // basic HashMap creation and set operation
* // Create a simple HashMap with key-value pairs
* const map = new HashMap<number, string>([
* [1, 'one'],
* [2, 'two'],
* [3, 'three']
* ]);
*
* // Verify size
* console.log(map.size); // 3;
*
* // Set a new key-value pair
* map.set(4, 'four');
* console.log(map.size); // 4;
*
* // Verify entries
* console.log([...map.entries()]); // length: 4;
* @example
* // HashMap get and has operations
* const map = new HashMap<string, number>([
* ['apple', 1],
* ['banana', 2],
* ['cherry', 3]
* ]);
*
* // Check if key exists
* console.log(map.has('apple')); // true;
* console.log(map.has('date')); // false;
*
* // Get value by key
* console.log(map.get('banana')); // 2;
* console.log(map.get('grape')); // undefined;
*
* // Get all keys and values
* const keys = [...map.keys()];
* const values = [...map.values()];
* console.log(keys); // contains 'apple';
* console.log(values); // contains 3;
* @example
* // HashMap iteration and filter operations
* const map = new HashMap<number, string>([
* [1, 'Alice'],
* [2, 'Bob'],
* [3, 'Charlie'],
* [4, 'Diana'],
* [5, 'Eve']
* ]);
*
* // Iterate through entries
* const entries: [number, string][] = [];
* for (const [key, value] of map) {
* entries.push([key, value]);
* }
* console.log(entries); // length: 5;
*
* // Filter operation (for iteration with collection methods)
* const filtered = [...map].filter(([key]) => key > 2);
* console.log(filtered.length); // 3;
*
* // Map operation
* const values = [...map.values()].map(v => v.length);
* console.log(values); // contains 3; // 'Bob', 'Eve'
* console.log(values); // contains 7;
* @example
* // HashMap for user session caching O(1) performance
* interface UserSession {
* userId: number;
* username: string;
* loginTime: number;
* lastActivity: number;
* }
*
* // HashMap provides O(1) average-case performance for set/get/delete
* // Perfect for session management with fast lookups
* const sessionCache = new HashMap<string, UserSession>();
*
* // Simulate user sessions
* const sessions: [string, UserSession][] = [
* ['session_001', { userId: 1, username: 'alice', loginTime: 1000, lastActivity: 1050 }],
* ['session_002', { userId: 2, username: 'bob', loginTime: 1100, lastActivity: 1150 }],
* ['session_003', { userId: 3, username: 'charlie', loginTime: 1200, lastActivity: 1250 }]
* ];
*
* // Store sessions with O(1) insertion
* for (const [token, session] of sessions) {
* sessionCache.set(token, session);
* }
*
* console.log(sessionCache.size); // 3;
*
* // Retrieve session with O(1) lookup
* const userSession = sessionCache.get('session_001');
* console.log(userSession?.username); // 'alice';
* console.log(userSession?.userId); // 1;
*
* // Update session with O(1) operation
* if (userSession) {
* userSession.lastActivity = 2000;
* sessionCache.set('session_001', userSession);
* }
*
* // Check updated value
* const updated = sessionCache.get('session_001');
* console.log(updated?.lastActivity); // 2000;
*
* // Cleanup: delete expired sessions
* sessionCache.delete('session_002');
* console.log(sessionCache.has('session_002')); // false;
*
* // Verify remaining sessions
* console.log(sessionCache.size); // 2;
*
* // Get all active sessions
* const activeCount = [...sessionCache.values()].length;
* console.log(activeCount); // 2;
*/
export declare class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K, V> {
/**
* Create a HashMap and optionally bulk-insert entries.
* @remarks Time O(N), Space O(N)
* @param [entryOrRawElements] - Iterable of entries or raw elements to insert.
* @param [options] - Options: hash function and optional record-to-entry converter.
* @returns New HashMap instance.
*/
constructor(entryOrRawElements?: Iterable<R | [K, V]>, options?: HashMapOptions<K, V, R>);
protected _store: {
[key: string]: HashMapStoreItem<K, V>;
};
/**
* Get the internal store for non-object keys.
* @remarks Time O(1), Space O(1)
* @returns Internal record of string→{key,value}.
*/
get store(): {
[p: string]: HashMapStoreItem<K, V>;
};
protected _objMap: Map<object, V>;
/**
* Get the internal Map used for object/function keys.
* @remarks Time O(1), Space O(1)
* @returns Map of object→value.
*/
get objMap(): Map<object, V>;
protected _toEntryFn?: (rawElement: R) => [K, V];
/**
* Get the raw→entry converter function if present.
* @remarks Time O(1), Space O(1)
* @returns Converter function or undefined.
*/
get toEntryFn(): ((rawElement: R) => [K, V]) | undefined;
protected _size: number;
/**
* Get the number of distinct keys stored.
* @remarks Time O(1), Space O(1)
* @returns Current size.
*/
get size(): number;
protected _hashFn: (key: K) => string;
/**
* Get the current hash function for non-object keys.
* @remarks Time O(1), Space O(1)
* @returns Hash function.
*/
get hashFn(): (key: K) => string;
/**
* Check whether the map is empty.
* @remarks Time O(1), Space O(1)
* @returns True if size is 0.
*/
isEmpty(): boolean;
/**
* Remove all entries and reset counters.
* @remarks Time O(N), Space O(1)
* @returns void
*/
clear(): void;
/**
* Type guard: check if a raw value is a [key, value] entry.
* @remarks Time O(1), Space O(1)
* @returns True if the value is a 2-tuple.
*/
isEntry(rawElement: any): rawElement is [K, V];
/**
* Insert or replace a single entry.
* @remarks Time O(1), Space O(1)
* @param key - Key.
* @param value - Value.
* @returns True when the operation succeeds.
*/
set(key: K, value: V): boolean;
/**
* Insert many entries from an iterable.
* @remarks Time O(N), Space O(N)
* @param entryOrRawElements - Iterable of entries or raw elements to insert.
* @returns Array of per-entry results.
*/
setMany(entryOrRawElements: Iterable<R | [K, V]>): boolean[];
/**
* Get the value for a key.
* @remarks Time O(1), Space O(1)
* @param key - Key to look up.
* @returns Value or undefined.
*/
get(key: K): V | undefined;
/**
* Check if a key exists.
* @remarks Time O(1), Space O(1)
* @param key - Key to test.
* @returns True if present.
*/
has(key: K): boolean;
/**
* Delete an entry by key.
* @remarks Time O(1), Space O(1)
* @param key - Key to delete.
* @returns True if the key was found and removed.
*/
delete(key: K): boolean;
/**
* Replace the hash function and rehash the non-object store.
* @remarks Time O(N), Space O(N)
* @param fn - New hash function for non-object keys.
* @returns This map instance.
*/
setHashFn(fn: (key: K) => string): this;
/**
* Deep clone this map, preserving hashing behavior.
* @remarks Time O(N), Space O(N)
* @returns A new map with the same content.
*/
clone(): this;
/**
* Map values to a new map with the same keys.
* @remarks Time O(N), Space O(N)
* @template VM
* @param callbackfn - Mapping function (key, value, index, map) → newValue.
* @param [thisArg] - Value for `this` inside the callback.
* @returns A new map with transformed values.
*/
map<VM>(callbackfn: EntryCallback<K, V, VM>, thisArg?: any): any;
/**
* Filter entries into a new map.
* @remarks Time O(N), Space O(N)
* @param predicate - Predicate (key, value, index, map) → boolean.
* @param [thisArg] - Value for `this` inside the predicate.
* @returns A new map containing entries that satisfied the predicate.
*/
filter(predicate: EntryCallback<K, V, boolean>, thisArg?: any): any;
/**
* (Protected) Create a like-kind instance and seed it from an iterable.
* @remarks Time O(N), Space O(N)
* @template TK
* @template TV
* @template TR
* @param [entries] - Iterable used to seed the new map.
* @param [options] - Options forwarded to the constructor.
* @returns A like-kind map instance.
*/
protected _createLike<TK = K, TV = V, TR = [TK, TV]>(entries?: Iterable<[TK, TV] | TR>, options?: any): any;
protected _rehashNoObj(): void;
protected _getIterator(): IterableIterator<[K, V]>;
protected _isObjKey(key: any): key is object | ((...args: any[]) => any);
protected _getNoObjKey(key: K): string;
}
/**
* Hash-based map that preserves insertion order via a doubly-linked list.
* @remarks Time O(1), Space O(1)
* @template K
* @template V
* @template R
* @example examples will be generated by unit test
*/
export declare class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K, V> {
protected readonly _sentinel: HashMapLinkedNode<K, V | undefined>;
/**
* Create a LinkedHashMap and optionally bulk-insert entries.
* @remarks Time O(N), Space O(N)
* @param [entryOrRawElements] - Iterable of entries or raw elements to insert.
* @param [options] - Options: hash functions and optional record-to-entry converter.
* @returns New LinkedHashMap instance.
*/
constructor(entryOrRawElements?: Iterable<R | [K, V]>, options?: LinkedHashMapOptions<K, V, R>);
protected _hashFn: (key: K) => string;
get hashFn(): (key: K) => string;
protected _objHashFn: (key: K) => object;
/**
* Get the hash function for object/weak keys.
* @remarks Time O(1), Space O(1)
* @returns Object-hash function.
*/
get objHashFn(): (key: K) => object;
protected _noObjMap: Record<string, HashMapLinkedNode<K, V | undefined>>;
/**
* Get the internal record for non-object keys.
* @remarks Time O(1), Space O(1)
* @returns Record of hash→node.
*/
get noObjMap(): Record<string, HashMapLinkedNode<K, V | undefined>>;
protected _objMap: WeakMap<object, HashMapLinkedNode<K, V | undefined>>;
get objMap(): WeakMap<object, HashMapLinkedNode<K, V | undefined>>;
protected _head: HashMapLinkedNode<K, V | undefined>;
/**
* Get the head node (first entry) sentinel link.
* @remarks Time O(1), Space O(1)
* @returns Head node or sentinel.
*/
get head(): HashMapLinkedNode<K, V | undefined>;
protected _tail: HashMapLinkedNode<K, V | undefined>;
/**
* Get the tail node (last entry) sentinel link.
* @remarks Time O(1), Space O(1)
* @returns Tail node or sentinel.
*/
get tail(): HashMapLinkedNode<K, V | undefined>;
protected _toEntryFn?: (rawElement: R) => [K, V];
get toEntryFn(): ((rawElement: R) => [K, V]) | undefined;
protected _size: number;
get size(): number;
/**
* Get the first [key, value] pair.
* @remarks Time O(1), Space O(1)
* @returns First entry or undefined when empty.
*/
get first(): [K, V] | undefined;
/**
* Get the last [key, value] pair.
* @remarks Time O(1), Space O(1)
* @returns Last entry or undefined when empty.
*/
get last(): [K, V] | undefined;
/**
* Iterate from head → tail.
* @remarks Time O(N), Space O(1)
* @returns Iterator of [key, value].
*/
begin(): Generator<(K | V | undefined)[], void, unknown>;
/**
* Iterate from tail → head.
* @remarks Time O(N), Space O(1)
* @returns Iterator of [key, value].
*/
reverseBegin(): Generator<(K | V | undefined)[], void, unknown>;
/**
* Insert or replace a single entry; preserves insertion order.
* @remarks Time O(1), Space O(1)
* @param key - Key.
* @param [value] - Value.
* @returns True when the operation succeeds.
*/
set(key: K, value?: V): boolean;
setMany(entryOrRawElements: Iterable<R | [K, V]>): boolean[];
has(key: K): boolean;
get(key: K): V | undefined;
/**
* Get the value at a given index in insertion order.
* @remarks Time O(N), Space O(1)
* @param index - Zero-based index.
* @returns Value at the index.
*/
at(index: number): V | undefined;
delete(key: K): boolean;
/**
* Delete the first entry that matches a predicate.
* @remarks Time O(N), Space O(1)
* @param predicate - Function (key, value, index, map) → boolean to decide deletion.
* @returns True if an entry was removed.
*/
deleteWhere(predicate: (key: K, value: V | undefined, index: number, map: this) => boolean): boolean;
/**
* Delete the entry at a given index.
* @remarks Time O(N), Space O(1)
* @param index - Zero-based index.
* @returns True if removed.
*/
deleteAt(index: number): boolean;
isEmpty(): boolean;
isEntry(rawElement: any): rawElement is [K, V];
clear(): void;
clone(): any;
filter(predicate: EntryCallback<K, V, boolean>, thisArg?: any): any;
/**
* Map each entry to a new [key, value] pair and preserve order.
* @remarks Time O(N), Space O(N)
* @template MK
* @template MV
* @param callback - Mapping function (key, value, index, map) → [newKey, newValue].
* @param [thisArg] - Value for `this` inside the callback.
* @returns A new map of the same class with transformed entries.
*/
map<MK, MV>(callback: EntryCallback<K, V, [MK, MV]>, thisArg?: any): any;
protected _getIterator(): IterableIterator<[K, V]>;
protected _deleteNode(node: HashMapLinkedNode<K, V | undefined>): boolean;
protected _createLike<TK = K, TV = V, TR = [TK, TV]>(entries?: Iterable<[TK, TV] | TR>, options?: any): any;
}