/** * data-structure-typed * * @author Pablo Zeng * @copyright Copyright (c) 2022 Pablo Zeng * @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 * // 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(); * * // 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; * @example * // Aggregate values * const counts = new HashMap([['a', 5], ['b', 3], ['c', 8]]); * * const total = counts.reduce((sum, v) => sum + (v ?? 0), 0); * console.log(total); // 16; * @example * // Iterate over entries * const map = new HashMap([['x', 1], ['y', 2]]); * const keys: string[] = []; * * map.forEach((v, k) => keys.push(k)); * console.log(keys.sort()); // ['x', 'y']; */ export declare class HashMap extends IterableEntryBase { /** * 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, options?: HashMapOptions); protected _store: { [key: string]: HashMapStoreItem; }; /** * 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; }; protected _objMap: Map; /** * Get the internal Map used for object/function keys. * @remarks Time O(1), Space O(1) * @returns Map of object→value. */ get objMap(): Map; protected readonly _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. * @example * // Check if empty * const map = new HashMap(); * console.log(map.isEmpty()); // true; */ isEmpty(): boolean; /** * Remove all entries and reset counters. * @remarks Time O(N), Space O(1) * @returns void * @example * // Remove all entries * const map = new HashMap([['a', 1], ['b', 2]]); * map.clear(); * console.log(map.isEmpty()); // true; */ 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: unknown): 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. * @example * // basic HashMap creation and set operation * // Create a simple HashMap with key-value pairs * const map = new HashMap([ * [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; */ set(key: K, value: V): this; /** * 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. * @example * // Add multiple entries * const map = new HashMap(); * map.setMany([['a', 1], ['b', 2], ['c', 3]]); * console.log(map.size); // 3; */ setMany(entryOrRawElements: Iterable): boolean[]; /** * Get the value for a key. * @remarks Time O(1), Space O(1) * @param key - Key to look up. * @returns Value or undefined. * @example * // HashMap get and has operations * const map = new HashMap([ * ['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; */ 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. * @example * // Check key existence * const map = new HashMap([['a', 1], ['b', 2]]); * * console.log(map.has('a')); // true; * console.log(map.has('z')); // false; */ 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. * @example * // Remove entries by key * const map = new HashMap([['x', 10], ['y', 20], ['z', 30]]); * * console.log(map.delete('y')); // true; * console.log(map.has('y')); // false; * console.log(map.size); // 2; */ 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. * @example * // Create independent copy * const map = new HashMap([['a', 1]]); * const copy = map.clone(); * copy.set('a', 99); * console.log(map.get('a')); // 1; */ 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. * @example * // Transform all values * const prices = new HashMap([['apple', 1], ['banana', 2]]); * * const doubled = prices.map(v => (v ?? 0) * 2); * console.log(doubled.get('apple')); // 2; * console.log(doubled.get('banana')); // 4; */ map(callbackfn: EntryCallback, thisArg?: unknown): HashMap; /** * 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. * @example * // HashMap iteration and filter operations * const map = new HashMap([ * [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; */ filter(predicate: EntryCallback, thisArg?: unknown): this; /** * (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(entries?: Iterable<[TK, TV] | TR>, options?: Record): this; protected _rehashNoObj(): void; protected _getIterator(): IterableIterator<[K, V]>; protected _isObjKey(key: unknown): key is object | ((...args: unknown[]) => unknown); 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 extends IterableEntryBase { protected readonly _sentinel: HashMapLinkedNode; /** * 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, options?: LinkedHashMapOptions); 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>; /** * Get the internal record for non-object keys. * @remarks Time O(1), Space O(1) * @returns Record of hash→node. */ get noObjMap(): Record>; protected _objMap: WeakMap>; get objMap(): WeakMap>; protected _head: HashMapLinkedNode; /** * Get the head node (first entry) sentinel link. * @remarks Time O(1), Space O(1) * @returns Head node or sentinel. */ get head(): HashMapLinkedNode; protected _tail: HashMapLinkedNode; /** * Get the tail node (last entry) sentinel link. * @remarks Time O(1), Space O(1) * @returns Tail node or sentinel. */ get tail(): HashMapLinkedNode; protected readonly _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 This map (for chaining). */ set(key: K, value?: V): this; setMany(entryOrRawElements: Iterable): 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 The removed entry [key, value]. * @throws {RangeError} If index is out of bounds. */ deleteAt(index: number): [K, V | undefined]; isEmpty(): boolean; isEntry(rawElement: unknown): rawElement is [K, V]; clear(): void; clone(): this; filter(predicate: EntryCallback, thisArg?: unknown): this; /** * 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(callback: EntryCallback, thisArg?: unknown): LinkedHashMap; protected _getIterator(): IterableIterator<[K, V]>; protected _deleteNode(node: HashMapLinkedNode): boolean; protected _createLike(entries?: Iterable<[TK, TV] | TR>, options?: Record): this; }