Socket
Socket
Sign inDemoInstall

data-structure-typed

Package Overview
Dependencies
Maintainers
1
Versions
201
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

data-structure-typed - npm Package Compare versions

Comparing version 1.46.3 to 1.46.4

22

benchmark/report.json

@@ -6,4 +6,4 @@ {

"test name": "1,000,000 set",
"time taken (ms)": "172.42",
"executions per sec": "5.80",
"time taken (ms)": "217.67",
"executions per sec": "4.59",
"sample deviation": "0.02"

@@ -13,17 +13,5 @@ },

"test name": "1,000,000 CPT set",
"time taken (ms)": "172.27",
"executions per sec": "5.80",
"sample deviation": "0.02"
},
{
"test name": "1,000,000 set & get",
"time taken (ms)": "182.19",
"executions per sec": "5.49",
"sample deviation": "0.02"
},
{
"test name": "1,000,000 CPT set & get",
"time taken (ms)": "175.65",
"executions per sec": "5.69",
"sample deviation": "0.02"
"time taken (ms)": "176.11",
"executions per sec": "5.68",
"sample deviation": "0.03"
}

@@ -30,0 +18,0 @@ ],

@@ -11,3 +11,3 @@ # Changelog

## [v1.46.3](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
## [v1.46.4](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)

@@ -14,0 +14,0 @@ ### Changes

@@ -8,17 +8,17 @@ /**

*/
import { HashMapLinkedNode, IterableWithSizeOrLength } from '../../types';
import { HashMapLinkedNode, HashMapOptions } from '../../types';
export declare class HashMap<K = any, V = any> {
readonly OBJ_KEY_INDEX: symbol;
protected _nodes: HashMapLinkedNode<K, V>[];
protected _orgMap: Record<string, HashMapLinkedNode<K, V>>;
protected _head: HashMapLinkedNode<K, V>;
protected _tail: HashMapLinkedNode<K, V>;
protected readonly _sentinel: HashMapLinkedNode<K, V>;
protected _noObjMap: Record<string, HashMapLinkedNode<K, V | undefined>>;
protected _objMap: WeakMap<WeakKey, HashMapLinkedNode<K, V | undefined>>;
protected _head: HashMapLinkedNode<K, V | undefined>;
protected _tail: HashMapLinkedNode<K, V | undefined>;
protected readonly _sentinel: HashMapLinkedNode<K, V | undefined>;
protected _hashFn: (key: K) => string;
protected _objHashFn: (key: K) => WeakKey;
/**
* The constructor initializes a HashMap object with an optional initial set of key-value pairs.
* @param {Iterable<[K, V]>} elements - The `hashMap` parameter is an optional parameter of type `HashMapOptions<[K,
* V]>`. It is an array of key-value pairs, where each pair is represented as an array `[K, V]`. The
* `K` represents the type of the key and `V` represents the
* The constructor initializes a HashMapLinkedNode with an optional iterable of key-value pairs.
* @param options - The `options` parameter is an object that contains the `elements` property. The
* `elements` property is an iterable that contains key-value pairs represented as arrays `[K, V]`.
*/
constructor(elements?: IterableWithSizeOrLength<[K, V]>);
constructor(options?: HashMapOptions<K, V>);
protected _size: number;

@@ -47,3 +47,3 @@ get size(): number;

*/
begin(): Generator<(K | V)[], void, unknown>;
begin(): Generator<(K | V | undefined)[], void, unknown>;
/**

@@ -53,3 +53,3 @@ * The function `reverseBegin()` iterates over a linked list in reverse order, yielding each node's

*/
reverseBegin(): Generator<(K | V)[], void, unknown>;
reverseBegin(): Generator<(K | V | undefined)[], void, unknown>;
/**

@@ -65,6 +65,5 @@ * Time Complexity: O(1)

* value associated with the key being set in the data structure.
* @param {boolean} isObjectKey - A boolean flag indicating whether the key is an object key or not.
* @returns the size of the data structure after the key-value pair has been set.
*/
set(key: K, value?: V, isObjectKey?: boolean): number;
set(key: K, value?: V): number;
/**

@@ -78,11 +77,8 @@ * Time Complexity: O(1)

* of any type, but typically it is a string or symbol.
* @param {boolean} isObjectKey - The `isObjectKey` parameter is a boolean flag that indicates
* whether the `key` parameter is an object key or not. If `isObjectKey` is `true`, it means that
* `key` is an object key. If `isObjectKey` is `false`, it means that `key`
* @returns The value associated with the given key is being returned. If the key is an object key,
* the value is retrieved from the `_nodes` array using the index stored in the `OBJ_KEY_INDEX`
* property of the key. If the key is a string key, the value is retrieved from the `_orgMap` object
* property of the key. If the key is a string key, the value is retrieved from the `_noObjMap` object
* using the key itself. If the key is not found, `undefined` is
*/
get(key: K, isObjectKey?: boolean): V | undefined;
get(key: K): V | undefined;
/**

@@ -107,9 +103,6 @@ * Time Complexity: O(n), where n is the index.

* It can be of any type, but typically it is a string or an object.
* @param {boolean} isObjectKey - The `isObjectKey` parameter is a boolean flag that indicates
* whether the `key` parameter is an object key or not. If `isObjectKey` is `true`, it means that the
* `key` parameter is an object key. If `isObjectKey` is `false`, it means that the
* @returns a boolean value. It returns `true` if the deletion was successful, and `false` if the key
* was not found.
*/
delete(key: K, isObjectKey?: boolean): boolean;
delete(key: K): boolean;
/**

@@ -151,2 +144,5 @@ * Time Complexity: O(n), where n is the index.

forEach(callback: (element: [K, V], index: number, hashMap: HashMap<K, V>) => void): void;
filter(predicate: (element: [K, V], map: HashMap<K, V>) => boolean): HashMap<K, V>;
map<NV>(callback: (element: [K, V], map: HashMap<K, V>) => NV): HashMap<K, NV>;
reduce<A>(callback: (accumulator: A, element: [K, V], map: HashMap<K, V>) => A, initialValue: A): A;
/**

@@ -169,3 +165,3 @@ * Time Complexity: O(n), where n is the number of elements in the HashMap.

*/
protected _deleteNode(node: HashMapLinkedNode<K, V>): void;
protected _deleteNode(node: HashMapLinkedNode<K, V | undefined>): void;
}

@@ -14,17 +14,23 @@ "use strict";

/**
* The constructor initializes a HashMap object with an optional initial set of key-value pairs.
* @param {Iterable<[K, V]>} elements - The `hashMap` parameter is an optional parameter of type `HashMapOptions<[K,
* V]>`. It is an array of key-value pairs, where each pair is represented as an array `[K, V]`. The
* `K` represents the type of the key and `V` represents the
* The constructor initializes a HashMapLinkedNode with an optional iterable of key-value pairs.
* @param options - The `options` parameter is an object that contains the `elements` property. The
* `elements` property is an iterable that contains key-value pairs represented as arrays `[K, V]`.
*/
constructor(elements = []) {
this.OBJ_KEY_INDEX = Symbol('OBJ_KEY_INDEX');
this._nodes = [];
this._orgMap = {};
constructor(options = {
elements: [],
hashFn: (key) => String(key),
objHashFn: (key) => key
}) {
this._noObjMap = {};
this._objMap = new WeakMap();
this._size = 0;
Object.setPrototypeOf(this._orgMap, null);
this._sentinel = {};
this._sentinel.prev = this._sentinel.next = this._head = this._tail = this._sentinel;
for (const el of elements) {
this.set(el[0], el[1]);
const { elements, hashFn, objHashFn } = options;
this._hashFn = hashFn;
this._objHashFn = objHashFn;
if (elements) {
for (const el of elements) {
this.set(el[0], el[1]);
}
}

@@ -92,48 +98,48 @@ }

* value associated with the key being set in the data structure.
* @param {boolean} isObjectKey - A boolean flag indicating whether the key is an object key or not.
* @returns the size of the data structure after the key-value pair has been set.
*/
set(key, value, isObjectKey = (0, utils_1.isObjOrFunc)(key)) {
let newTail;
if (isObjectKey) {
const index = key[this.OBJ_KEY_INDEX];
if (index !== undefined) {
this._nodes[index].value = value;
return this._size;
set(key, value) {
let node;
if ((0, utils_1.isWeakKey)(key)) {
// const hash = this._objHashFn(key);
const hash = key;
node = this._objMap.get(hash);
if (node) {
// If the node already exists, update its value
node.value = value;
}
Object.defineProperty(key, this.OBJ_KEY_INDEX, {
value: this._nodes.length,
configurable: true
});
newTail = {
key: key,
value: value,
prev: this._tail,
next: this._sentinel
};
this._nodes.push(newTail);
else {
// Create new node
node = { key: hash, value, prev: this._tail, next: this._sentinel };
// Add new nodes to _objMap and linked list
this._objMap.set(hash, node);
}
}
else {
const node = this._orgMap[key];
const hash = this._hashFn(key);
// Non-object keys are handled in the same way as the original implementation
node = this._noObjMap[hash];
if (node) {
node.value = value;
return this._size;
}
this._orgMap[key] = newTail = {
key: key,
value: value,
prev: this._tail,
next: this._sentinel
};
else {
this._noObjMap[hash] = node = {
key,
value,
prev: this._tail,
next: this._sentinel
};
}
}
if (this._size === 0) {
this._head = newTail;
this._sentinel.next = newTail;
this._head = node;
this._sentinel.next = node;
}
else {
this._tail.next = newTail;
this._tail.next = node;
}
this._tail = newTail;
this._sentinel.prev = newTail;
return ++this._size;
this._tail = node;
this._sentinel.prev = node;
this._size++;
return this._size;
}

@@ -148,17 +154,18 @@ /**

* of any type, but typically it is a string or symbol.
* @param {boolean} isObjectKey - The `isObjectKey` parameter is a boolean flag that indicates
* whether the `key` parameter is an object key or not. If `isObjectKey` is `true`, it means that
* `key` is an object key. If `isObjectKey` is `false`, it means that `key`
* @returns The value associated with the given key is being returned. If the key is an object key,
* the value is retrieved from the `_nodes` array using the index stored in the `OBJ_KEY_INDEX`
* property of the key. If the key is a string key, the value is retrieved from the `_orgMap` object
* property of the key. If the key is a string key, the value is retrieved from the `_noObjMap` object
* using the key itself. If the key is not found, `undefined` is
*/
get(key, isObjectKey = (0, utils_1.isObjOrFunc)(key)) {
if (isObjectKey) {
const index = key[this.OBJ_KEY_INDEX];
return index !== undefined ? this._nodes[index].value : undefined;
get(key) {
if ((0, utils_1.isWeakKey)(key)) {
const hash = this._objHashFn(key);
const node = this._objMap.get(hash);
return node ? node.value : undefined;
}
const node = this._orgMap[key];
return node ? node.value : undefined;
else {
const hash = this._hashFn(key);
const node = this._noObjMap[hash];
return node ? node.value : undefined;
}
}

@@ -191,24 +198,28 @@ /**

* It can be of any type, but typically it is a string or an object.
* @param {boolean} isObjectKey - The `isObjectKey` parameter is a boolean flag that indicates
* whether the `key` parameter is an object key or not. If `isObjectKey` is `true`, it means that the
* `key` parameter is an object key. If `isObjectKey` is `false`, it means that the
* @returns a boolean value. It returns `true` if the deletion was successful, and `false` if the key
* was not found.
*/
delete(key, isObjectKey = (0, utils_1.isObjOrFunc)(key)) {
delete(key) {
let node;
if (isObjectKey) {
const index = key[this.OBJ_KEY_INDEX];
if (index === undefined)
return false;
delete key[this.OBJ_KEY_INDEX];
node = this._nodes[index];
delete this._nodes[index];
if ((0, utils_1.isWeakKey)(key)) {
const hash = this._objHashFn(key);
// Get nodes from WeakMap
node = this._objMap.get(hash);
if (!node) {
return false; // If the node does not exist, return false
}
// Remove nodes from WeakMap
this._objMap.delete(hash);
}
else {
node = this._orgMap[key];
if (node === undefined)
return false;
delete this._orgMap[key];
const hash = this._hashFn(key);
// Get nodes from noObjMap
node = this._noObjMap[hash];
if (!node) {
return false; // If the node does not exist, return false
}
// Remove nodes from orgMap
delete this._noObjMap[hash];
}
// Remove node from doubly linked list
this._deleteNode(node);

@@ -253,9 +264,3 @@ return true;

clear() {
// const OBJ_KEY_INDEX = this.OBJ_KEY_INDEX;
// this._nodes.forEach(el => {
// delete (<Record<symbol, number>><unknown>el.key)[OBJ_KEY_INDEX];
// });
this._nodes = [];
this._orgMap = {};
Object.setPrototypeOf(this._orgMap, null);
this._noObjMap = {};
this._size = 0;

@@ -281,2 +286,26 @@ this._head = this._tail = this._sentinel.prev = this._sentinel.next = this._sentinel;

}
filter(predicate) {
const filteredMap = new HashMap();
for (const [key, value] of this) {
if (predicate([key, value], this)) {
filteredMap.set(key, value);
}
}
return filteredMap;
}
map(callback) {
const mappedMap = new HashMap();
for (const [key, value] of this) {
const newValue = callback([key, value], this);
mappedMap.set(key, newValue);
}
return mappedMap;
}
reduce(callback, initialValue) {
let accumulator = initialValue;
for (const element of this) {
accumulator = callback(accumulator, element, this);
}
return accumulator;
}
/**

@@ -283,0 +312,0 @@ * Time Complexity: O(n), where n is the number of elements in the HashMap.

export * from './hash-table';
export * from './coordinate-map';
export * from './coordinate-set';
export * from './tree-map';
export * from './tree-set';
export * from './hash-map';

@@ -18,7 +18,3 @@ "use strict";

__exportStar(require("./hash-table"), exports);
__exportStar(require("./coordinate-map"), exports);
__exportStar(require("./coordinate-set"), exports);
__exportStar(require("./tree-map"), exports);
__exportStar(require("./tree-set"), exports);
__exportStar(require("./hash-map"), exports);
//# sourceMappingURL=index.js.map

@@ -7,1 +7,6 @@ export type HashMapLinkedNode<K, V> = {

};
export type HashMapOptions<K, V> = {
elements: Iterable<[K, V]>;
hashFn: (key: K) => string;
objHashFn: (key: K) => WeakKey;
};

@@ -1,7 +0,3 @@

export * from './coordinate-map';
export * from './coordinate-set';
export * from './hash-map';
export * from './hash-table';
export * from './tree-map';
export * from './tree-set';
export type HashFunction<K> = (key: K) => number;

@@ -17,8 +17,4 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./coordinate-map"), exports);
__exportStar(require("./coordinate-set"), exports);
__exportStar(require("./hash-map"), exports);
__exportStar(require("./hash-table"), exports);
__exportStar(require("./tree-map"), exports);
__exportStar(require("./tree-set"), exports);
//# sourceMappingURL=index.js.map

@@ -23,3 +23,3 @@ /**

export declare const throwRangeError: (message?: string) => void;
export declare const isObjOrFunc: (input: unknown) => input is Record<string, unknown> | ((...args: any[]) => any);
export declare const isWeakKey: (input: unknown) => input is WeakKey;
export declare const calcMinUnitsRequired: (totalQuantity: number, unitSize: number) => number;

@@ -12,3 +12,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.calcMinUnitsRequired = exports.isObjOrFunc = exports.throwRangeError = exports.rangeCheck = exports.getMSB = exports.trampolineAsync = exports.trampoline = exports.toThunk = exports.isThunk = exports.THUNK_SYMBOL = exports.arrayRemove = exports.uuidV4 = void 0;
exports.calcMinUnitsRequired = exports.isWeakKey = exports.throwRangeError = exports.rangeCheck = exports.getMSB = exports.trampolineAsync = exports.trampoline = exports.toThunk = exports.isThunk = exports.THUNK_SYMBOL = exports.arrayRemove = exports.uuidV4 = void 0;
const uuidV4 = function () {

@@ -84,9 +84,9 @@ return 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'.replace(/[x]/g, function (c) {

exports.throwRangeError = throwRangeError;
const isObjOrFunc = (input) => {
const isWeakKey = (input) => {
const inputType = typeof input;
return (inputType === 'object' && input !== null) || inputType === 'function';
};
exports.isObjOrFunc = isObjOrFunc;
exports.isWeakKey = isWeakKey;
const calcMinUnitsRequired = (totalQuantity, unitSize) => Math.floor((totalQuantity + unitSize - 1) / unitSize);
exports.calcMinUnitsRequired = calcMinUnitsRequired;
//# sourceMappingURL=utils.js.map

@@ -8,17 +8,17 @@ /**

*/
import { HashMapLinkedNode, IterableWithSizeOrLength } from '../../types';
import { HashMapLinkedNode, HashMapOptions } from '../../types';
export declare class HashMap<K = any, V = any> {
readonly OBJ_KEY_INDEX: symbol;
protected _nodes: HashMapLinkedNode<K, V>[];
protected _orgMap: Record<string, HashMapLinkedNode<K, V>>;
protected _head: HashMapLinkedNode<K, V>;
protected _tail: HashMapLinkedNode<K, V>;
protected readonly _sentinel: HashMapLinkedNode<K, V>;
protected _noObjMap: Record<string, HashMapLinkedNode<K, V | undefined>>;
protected _objMap: WeakMap<WeakKey, HashMapLinkedNode<K, V | undefined>>;
protected _head: HashMapLinkedNode<K, V | undefined>;
protected _tail: HashMapLinkedNode<K, V | undefined>;
protected readonly _sentinel: HashMapLinkedNode<K, V | undefined>;
protected _hashFn: (key: K) => string;
protected _objHashFn: (key: K) => WeakKey;
/**
* The constructor initializes a HashMap object with an optional initial set of key-value pairs.
* @param {Iterable<[K, V]>} elements - The `hashMap` parameter is an optional parameter of type `HashMapOptions<[K,
* V]>`. It is an array of key-value pairs, where each pair is represented as an array `[K, V]`. The
* `K` represents the type of the key and `V` represents the
* The constructor initializes a HashMapLinkedNode with an optional iterable of key-value pairs.
* @param options - The `options` parameter is an object that contains the `elements` property. The
* `elements` property is an iterable that contains key-value pairs represented as arrays `[K, V]`.
*/
constructor(elements?: IterableWithSizeOrLength<[K, V]>);
constructor(options?: HashMapOptions<K, V>);
protected _size: number;

@@ -47,3 +47,3 @@ get size(): number;

*/
begin(): Generator<(K | V)[], void, unknown>;
begin(): Generator<(K | V | undefined)[], void, unknown>;
/**

@@ -53,3 +53,3 @@ * The function `reverseBegin()` iterates over a linked list in reverse order, yielding each node's

*/
reverseBegin(): Generator<(K | V)[], void, unknown>;
reverseBegin(): Generator<(K | V | undefined)[], void, unknown>;
/**

@@ -65,6 +65,5 @@ * Time Complexity: O(1)

* value associated with the key being set in the data structure.
* @param {boolean} isObjectKey - A boolean flag indicating whether the key is an object key or not.
* @returns the size of the data structure after the key-value pair has been set.
*/
set(key: K, value?: V, isObjectKey?: boolean): number;
set(key: K, value?: V): number;
/**

@@ -78,11 +77,8 @@ * Time Complexity: O(1)

* of any type, but typically it is a string or symbol.
* @param {boolean} isObjectKey - The `isObjectKey` parameter is a boolean flag that indicates
* whether the `key` parameter is an object key or not. If `isObjectKey` is `true`, it means that
* `key` is an object key. If `isObjectKey` is `false`, it means that `key`
* @returns The value associated with the given key is being returned. If the key is an object key,
* the value is retrieved from the `_nodes` array using the index stored in the `OBJ_KEY_INDEX`
* property of the key. If the key is a string key, the value is retrieved from the `_orgMap` object
* property of the key. If the key is a string key, the value is retrieved from the `_noObjMap` object
* using the key itself. If the key is not found, `undefined` is
*/
get(key: K, isObjectKey?: boolean): V | undefined;
get(key: K): V | undefined;
/**

@@ -107,9 +103,6 @@ * Time Complexity: O(n), where n is the index.

* It can be of any type, but typically it is a string or an object.
* @param {boolean} isObjectKey - The `isObjectKey` parameter is a boolean flag that indicates
* whether the `key` parameter is an object key or not. If `isObjectKey` is `true`, it means that the
* `key` parameter is an object key. If `isObjectKey` is `false`, it means that the
* @returns a boolean value. It returns `true` if the deletion was successful, and `false` if the key
* was not found.
*/
delete(key: K, isObjectKey?: boolean): boolean;
delete(key: K): boolean;
/**

@@ -151,2 +144,5 @@ * Time Complexity: O(n), where n is the index.

forEach(callback: (element: [K, V], index: number, hashMap: HashMap<K, V>) => void): void;
filter(predicate: (element: [K, V], map: HashMap<K, V>) => boolean): HashMap<K, V>;
map<NV>(callback: (element: [K, V], map: HashMap<K, V>) => NV): HashMap<K, NV>;
reduce<A>(callback: (accumulator: A, element: [K, V], map: HashMap<K, V>) => A, initialValue: A): A;
/**

@@ -169,3 +165,3 @@ * Time Complexity: O(n), where n is the number of elements in the HashMap.

*/
protected _deleteNode(node: HashMapLinkedNode<K, V>): void;
protected _deleteNode(node: HashMapLinkedNode<K, V | undefined>): void;
}

@@ -8,22 +8,30 @@ /**

*/
import { isObjOrFunc, rangeCheck } from '../../utils';
import { isWeakKey, rangeCheck } from '../../utils';
export class HashMap {
OBJ_KEY_INDEX = Symbol('OBJ_KEY_INDEX');
_nodes = [];
_orgMap = {};
_noObjMap = {};
_objMap = new WeakMap();
_head;
_tail;
_sentinel;
_hashFn;
_objHashFn;
/**
* The constructor initializes a HashMap object with an optional initial set of key-value pairs.
* @param {Iterable<[K, V]>} elements - The `hashMap` parameter is an optional parameter of type `HashMapOptions<[K,
* V]>`. It is an array of key-value pairs, where each pair is represented as an array `[K, V]`. The
* `K` represents the type of the key and `V` represents the
* The constructor initializes a HashMapLinkedNode with an optional iterable of key-value pairs.
* @param options - The `options` parameter is an object that contains the `elements` property. The
* `elements` property is an iterable that contains key-value pairs represented as arrays `[K, V]`.
*/
constructor(elements = []) {
Object.setPrototypeOf(this._orgMap, null);
constructor(options = {
elements: [],
hashFn: (key) => String(key),
objHashFn: (key) => key
}) {
this._sentinel = {};
this._sentinel.prev = this._sentinel.next = this._head = this._tail = this._sentinel;
for (const el of elements) {
this.set(el[0], el[1]);
const { elements, hashFn, objHashFn } = options;
this._hashFn = hashFn;
this._objHashFn = objHashFn;
if (elements) {
for (const el of elements) {
this.set(el[0], el[1]);
}
}

@@ -92,48 +100,48 @@ }

* value associated with the key being set in the data structure.
* @param {boolean} isObjectKey - A boolean flag indicating whether the key is an object key or not.
* @returns the size of the data structure after the key-value pair has been set.
*/
set(key, value, isObjectKey = isObjOrFunc(key)) {
let newTail;
if (isObjectKey) {
const index = key[this.OBJ_KEY_INDEX];
if (index !== undefined) {
this._nodes[index].value = value;
return this._size;
set(key, value) {
let node;
if (isWeakKey(key)) {
// const hash = this._objHashFn(key);
const hash = key;
node = this._objMap.get(hash);
if (node) {
// If the node already exists, update its value
node.value = value;
}
Object.defineProperty(key, this.OBJ_KEY_INDEX, {
value: this._nodes.length,
configurable: true
});
newTail = {
key: key,
value: value,
prev: this._tail,
next: this._sentinel
};
this._nodes.push(newTail);
else {
// Create new node
node = { key: hash, value, prev: this._tail, next: this._sentinel };
// Add new nodes to _objMap and linked list
this._objMap.set(hash, node);
}
}
else {
const node = this._orgMap[key];
const hash = this._hashFn(key);
// Non-object keys are handled in the same way as the original implementation
node = this._noObjMap[hash];
if (node) {
node.value = value;
return this._size;
}
this._orgMap[key] = newTail = {
key: key,
value: value,
prev: this._tail,
next: this._sentinel
};
else {
this._noObjMap[hash] = node = {
key,
value,
prev: this._tail,
next: this._sentinel
};
}
}
if (this._size === 0) {
this._head = newTail;
this._sentinel.next = newTail;
this._head = node;
this._sentinel.next = node;
}
else {
this._tail.next = newTail;
this._tail.next = node;
}
this._tail = newTail;
this._sentinel.prev = newTail;
return ++this._size;
this._tail = node;
this._sentinel.prev = node;
this._size++;
return this._size;
}

@@ -148,17 +156,18 @@ /**

* of any type, but typically it is a string or symbol.
* @param {boolean} isObjectKey - The `isObjectKey` parameter is a boolean flag that indicates
* whether the `key` parameter is an object key or not. If `isObjectKey` is `true`, it means that
* `key` is an object key. If `isObjectKey` is `false`, it means that `key`
* @returns The value associated with the given key is being returned. If the key is an object key,
* the value is retrieved from the `_nodes` array using the index stored in the `OBJ_KEY_INDEX`
* property of the key. If the key is a string key, the value is retrieved from the `_orgMap` object
* property of the key. If the key is a string key, the value is retrieved from the `_noObjMap` object
* using the key itself. If the key is not found, `undefined` is
*/
get(key, isObjectKey = isObjOrFunc(key)) {
if (isObjectKey) {
const index = key[this.OBJ_KEY_INDEX];
return index !== undefined ? this._nodes[index].value : undefined;
get(key) {
if (isWeakKey(key)) {
const hash = this._objHashFn(key);
const node = this._objMap.get(hash);
return node ? node.value : undefined;
}
const node = this._orgMap[key];
return node ? node.value : undefined;
else {
const hash = this._hashFn(key);
const node = this._noObjMap[hash];
return node ? node.value : undefined;
}
}

@@ -191,24 +200,28 @@ /**

* It can be of any type, but typically it is a string or an object.
* @param {boolean} isObjectKey - The `isObjectKey` parameter is a boolean flag that indicates
* whether the `key` parameter is an object key or not. If `isObjectKey` is `true`, it means that the
* `key` parameter is an object key. If `isObjectKey` is `false`, it means that the
* @returns a boolean value. It returns `true` if the deletion was successful, and `false` if the key
* was not found.
*/
delete(key, isObjectKey = isObjOrFunc(key)) {
delete(key) {
let node;
if (isObjectKey) {
const index = key[this.OBJ_KEY_INDEX];
if (index === undefined)
return false;
delete key[this.OBJ_KEY_INDEX];
node = this._nodes[index];
delete this._nodes[index];
if (isWeakKey(key)) {
const hash = this._objHashFn(key);
// Get nodes from WeakMap
node = this._objMap.get(hash);
if (!node) {
return false; // If the node does not exist, return false
}
// Remove nodes from WeakMap
this._objMap.delete(hash);
}
else {
node = this._orgMap[key];
if (node === undefined)
return false;
delete this._orgMap[key];
const hash = this._hashFn(key);
// Get nodes from noObjMap
node = this._noObjMap[hash];
if (!node) {
return false; // If the node does not exist, return false
}
// Remove nodes from orgMap
delete this._noObjMap[hash];
}
// Remove node from doubly linked list
this._deleteNode(node);

@@ -253,9 +266,3 @@ return true;

clear() {
// const OBJ_KEY_INDEX = this.OBJ_KEY_INDEX;
// this._nodes.forEach(el => {
// delete (<Record<symbol, number>><unknown>el.key)[OBJ_KEY_INDEX];
// });
this._nodes = [];
this._orgMap = {};
Object.setPrototypeOf(this._orgMap, null);
this._noObjMap = {};
this._size = 0;

@@ -281,2 +288,26 @@ this._head = this._tail = this._sentinel.prev = this._sentinel.next = this._sentinel;

}
filter(predicate) {
const filteredMap = new HashMap();
for (const [key, value] of this) {
if (predicate([key, value], this)) {
filteredMap.set(key, value);
}
}
return filteredMap;
}
map(callback) {
const mappedMap = new HashMap();
for (const [key, value] of this) {
const newValue = callback([key, value], this);
mappedMap.set(key, newValue);
}
return mappedMap;
}
reduce(callback, initialValue) {
let accumulator = initialValue;
for (const element of this) {
accumulator = callback(accumulator, element, this);
}
return accumulator;
}
/**

@@ -283,0 +314,0 @@ * Time Complexity: O(n), where n is the number of elements in the HashMap.

export * from './hash-table';
export * from './coordinate-map';
export * from './coordinate-set';
export * from './tree-map';
export * from './tree-set';
export * from './hash-map';
export * from './hash-table';
export * from './coordinate-map';
export * from './coordinate-set';
export * from './tree-map';
export * from './tree-set';
export * from './hash-map';

@@ -7,1 +7,6 @@ export type HashMapLinkedNode<K, V> = {

};
export type HashMapOptions<K, V> = {
elements: Iterable<[K, V]>;
hashFn: (key: K) => string;
objHashFn: (key: K) => WeakKey;
};

@@ -1,7 +0,3 @@

export * from './coordinate-map';
export * from './coordinate-set';
export * from './hash-map';
export * from './hash-table';
export * from './tree-map';
export * from './tree-set';
export type HashFunction<K> = (key: K) => number;

@@ -1,6 +0,2 @@

export * from './coordinate-map';
export * from './coordinate-set';
export * from './hash-map';
export * from './hash-table';
export * from './tree-map';
export * from './tree-set';

@@ -23,3 +23,3 @@ /**

export declare const throwRangeError: (message?: string) => void;
export declare const isObjOrFunc: (input: unknown) => input is Record<string, unknown> | ((...args: any[]) => any);
export declare const isWeakKey: (input: unknown) => input is WeakKey;
export declare const calcMinUnitsRequired: (totalQuantity: number, unitSize: number) => number;

@@ -62,3 +62,3 @@ export const uuidV4 = function () {

};
export const isObjOrFunc = (input) => {
export const isWeakKey = (input) => {
const inputType = typeof input;

@@ -65,0 +65,0 @@ return (inputType === 'object' && input !== null) || inputType === 'function';

{
"name": "data-structure-typed",
"version": "1.46.3",
"version": "1.46.4",
"description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.",

@@ -5,0 +5,0 @@ "main": "dist/cjs/index.js",

@@ -9,27 +9,37 @@ /**

import { isObjOrFunc, rangeCheck } from '../../utils';
import { HashMapLinkedNode, IterableWithSizeOrLength } from '../../types';
import { isWeakKey, rangeCheck } from '../../utils';
import { HashMapLinkedNode, HashMapOptions } from '../../types';
export class HashMap<K = any, V = any> {
readonly OBJ_KEY_INDEX = Symbol('OBJ_KEY_INDEX');
protected _nodes: HashMapLinkedNode<K, V>[] = [];
protected _orgMap: Record<string, HashMapLinkedNode<K, V>> = {};
protected _head: HashMapLinkedNode<K, V>;
protected _tail: HashMapLinkedNode<K, V>;
protected readonly _sentinel: HashMapLinkedNode<K, V>;
protected _noObjMap: Record<string, HashMapLinkedNode<K, V | undefined>> = {};
protected _objMap = new WeakMap<WeakKey, HashMapLinkedNode<K, V | undefined>>();
protected _head: HashMapLinkedNode<K, V | undefined>;
protected _tail: HashMapLinkedNode<K, V | undefined>;
protected readonly _sentinel: HashMapLinkedNode<K, V | undefined>;
protected _hashFn: (key: K) => string;
protected _objHashFn: (key: K) => WeakKey;
/**
* The constructor initializes a HashMap object with an optional initial set of key-value pairs.
* @param {Iterable<[K, V]>} elements - The `hashMap` parameter is an optional parameter of type `HashMapOptions<[K,
* V]>`. It is an array of key-value pairs, where each pair is represented as an array `[K, V]`. The
* `K` represents the type of the key and `V` represents the
* The constructor initializes a HashMapLinkedNode with an optional iterable of key-value pairs.
* @param options - The `options` parameter is an object that contains the `elements` property. The
* `elements` property is an iterable that contains key-value pairs represented as arrays `[K, V]`.
*/
constructor(elements: IterableWithSizeOrLength<[K, V]> = []) {
Object.setPrototypeOf(this._orgMap, null);
constructor(options: HashMapOptions<K, V> = {
elements: [],
hashFn: (key: K) => String(key),
objHashFn: (key: K) => (<WeakKey>key)
}) {
this._sentinel = <HashMapLinkedNode<K, V>>{};
this._sentinel.prev = this._sentinel.next = this._head = this._tail = this._sentinel;
for (const el of elements) {
this.set(el[0], el[1]);
const { elements, hashFn, objHashFn } = options;
this._hashFn = hashFn;
this._objHashFn = objHashFn;
if (elements) {
for (const el of elements) {
this.set(el[0], el[1]);
}
}
}

@@ -102,46 +112,50 @@

* value associated with the key being set in the data structure.
* @param {boolean} isObjectKey - A boolean flag indicating whether the key is an object key or not.
* @returns the size of the data structure after the key-value pair has been set.
*/
set(key: K, value?: V, isObjectKey: boolean = isObjOrFunc(key)) {
let newTail;
if (isObjectKey) {
const index = (<Record<symbol, number>>(<unknown>key))[this.OBJ_KEY_INDEX];
if (index !== undefined) {
this._nodes[<number>index].value = <V>value;
return this._size;
set(key: K, value?: V) {
let node;
if (isWeakKey(key)) {
// const hash = this._objHashFn(key);
const hash = key;
node = this._objMap.get(hash);
if (node) {
// If the node already exists, update its value
node.value = value;
} else {
// Create new node
node = { key: <K>hash, value, prev: this._tail, next: this._sentinel };
// Add new nodes to _objMap and linked list
this._objMap.set(hash, node);
}
Object.defineProperty(key, this.OBJ_KEY_INDEX, {
value: this._nodes.length,
configurable: true
});
newTail = {
key: key,
value: <V>value,
prev: this._tail,
next: this._sentinel
};
this._nodes.push(newTail);
} else {
const node = this._orgMap[<string>(<unknown>key)];
const hash = this._hashFn(key);
// Non-object keys are handled in the same way as the original implementation
node = this._noObjMap[hash];
if (node) {
node.value = <V>value;
return this._size;
node.value = value;
} else {
this._noObjMap[hash] = node = {
key,
value,
prev: this._tail,
next: this._sentinel
};
}
this._orgMap[<string>(<unknown>key)] = newTail = {
key: key,
value: <V>value,
prev: this._tail,
next: this._sentinel
};
}
if (this._size === 0) {
this._head = newTail;
this._sentinel.next = newTail;
this._head = node;
this._sentinel.next = node;
} else {
this._tail.next = newTail;
this._tail.next = node;
}
this._tail = newTail;
this._sentinel.prev = newTail;
return ++this._size;
this._tail = node;
this._sentinel.prev = node;
this._size++;
return this._size;
}

@@ -157,17 +171,17 @@

* of any type, but typically it is a string or symbol.
* @param {boolean} isObjectKey - The `isObjectKey` parameter is a boolean flag that indicates
* whether the `key` parameter is an object key or not. If `isObjectKey` is `true`, it means that
* `key` is an object key. If `isObjectKey` is `false`, it means that `key`
* @returns The value associated with the given key is being returned. If the key is an object key,
* the value is retrieved from the `_nodes` array using the index stored in the `OBJ_KEY_INDEX`
* property of the key. If the key is a string key, the value is retrieved from the `_orgMap` object
* property of the key. If the key is a string key, the value is retrieved from the `_noObjMap` object
* using the key itself. If the key is not found, `undefined` is
*/
get(key: K, isObjectKey: boolean = isObjOrFunc(key)) {
if (isObjectKey) {
const index = (<Record<symbol, number>>(<unknown>key))[this.OBJ_KEY_INDEX];
return index !== undefined ? this._nodes[index].value : undefined;
get(key: K): V | undefined {
if (isWeakKey(key)) {
const hash = this._objHashFn(key);
const node = this._objMap.get(hash);
return node ? node.value : undefined;
} else {
const hash = this._hashFn(key);
const node = this._noObjMap[hash];
return node ? node.value : undefined;
}
const node = this._orgMap[<string>(<unknown>key)];
return node ? node.value : undefined;
}

@@ -202,21 +216,33 @@

* It can be of any type, but typically it is a string or an object.
* @param {boolean} isObjectKey - The `isObjectKey` parameter is a boolean flag that indicates
* whether the `key` parameter is an object key or not. If `isObjectKey` is `true`, it means that the
* `key` parameter is an object key. If `isObjectKey` is `false`, it means that the
* @returns a boolean value. It returns `true` if the deletion was successful, and `false` if the key
* was not found.
*/
delete(key: K, isObjectKey: boolean = isObjOrFunc(key)) {
delete(key: K) {
let node;
if (isObjectKey) {
const index = (<Record<symbol, number>>(<unknown>key))[this.OBJ_KEY_INDEX];
if (index === undefined) return false;
delete (<Record<symbol, number>>(<unknown>key))[this.OBJ_KEY_INDEX];
node = this._nodes[index];
delete this._nodes[index];
if (isWeakKey(key)) {
const hash = this._objHashFn(key);
// Get nodes from WeakMap
node = this._objMap.get(hash);
if (!node) {
return false; // If the node does not exist, return false
}
// Remove nodes from WeakMap
this._objMap.delete(hash);
} else {
node = this._orgMap[<string>(<unknown>key)];
if (node === undefined) return false;
delete this._orgMap[<string>(<unknown>key)];
const hash = this._hashFn(key);
// Get nodes from noObjMap
node = this._noObjMap[hash];
if (!node) {
return false; // If the node does not exist, return false
}
// Remove nodes from orgMap
delete this._noObjMap[hash];
}
// Remove node from doubly linked list
this._deleteNode(node);

@@ -264,9 +290,3 @@ return true;

clear() {
// const OBJ_KEY_INDEX = this.OBJ_KEY_INDEX;
// this._nodes.forEach(el => {
// delete (<Record<symbol, number>><unknown>el.key)[OBJ_KEY_INDEX];
// });
this._nodes = [];
this._orgMap = {};
Object.setPrototypeOf(this._orgMap, null);
this._noObjMap = {};
this._size = 0;

@@ -294,2 +314,29 @@ this._head = this._tail = this._sentinel.prev = this._sentinel.next = this._sentinel;

filter(predicate: (element: [K, V], map: HashMap<K, V>) => boolean): HashMap<K, V> {
const filteredMap = new HashMap<K, V>();
for (const [key, value] of this) {
if (predicate([key, value], this)) {
filteredMap.set(key, value);
}
}
return filteredMap;
}
map<NV>(callback: (element: [K, V], map: HashMap<K, V>) => NV): HashMap<K, NV> {
const mappedMap = new HashMap<K, NV>();
for (const [key, value] of this) {
const newValue = callback([key, value], this);
mappedMap.set(key, newValue);
}
return mappedMap;
}
reduce<A>(callback: (accumulator: A, element: [K, V], map: HashMap<K, V>) => A, initialValue: A): A {
let accumulator = initialValue;
for (const element of this) {
accumulator = callback(accumulator, element, this);
}
return accumulator;
}
/**

@@ -319,14 +366,17 @@ * Time Complexity: O(n), where n is the number of elements in the HashMap.

*/
protected _deleteNode(node: HashMapLinkedNode<K, V>) {
protected _deleteNode(node: HashMapLinkedNode<K, V | undefined>) {
const { prev, next } = node;
prev.next = next;
next.prev = prev;
if (node === this._head) {
this._head = next;
}
if (node === this._tail) {
this._tail = prev;
}
this._size -= 1;
}
}
export * from './hash-table';
export * from './coordinate-map';
export * from './coordinate-set';
export * from './tree-map';
export * from './tree-set';
export * from './hash-map';

@@ -7,1 +7,7 @@ export type HashMapLinkedNode<K, V> = {

};
export type HashMapOptions<K, V> = {
elements: Iterable<[K, V]>;
hashFn: (key: K) => string;
objHashFn: (key: K) => WeakKey
}

@@ -1,8 +0,4 @@

export * from './coordinate-map';
export * from './coordinate-set';
export * from './hash-map';
export * from './hash-table';
export * from './tree-map';
export * from './tree-set';
export type HashFunction<K> = (key: K) => number;

@@ -96,3 +96,3 @@ /**

export const isObjOrFunc = (input: unknown): input is Record<string, unknown> | ((...args: any[]) => any) => {
export const isWeakKey = (input: unknown): input is WeakKey => {
const inputType = typeof input;

@@ -99,0 +99,0 @@ return (inputType === 'object' && input !== null) || inputType === 'function';

@@ -17,2 +17,3 @@ import { HashMap } from '../../../../src';

});
if (isCompetitor) {

@@ -27,2 +28,15 @@ suite.add(`${MILLION.toLocaleString()} CPT set`, () => {

}
suite.add(`${MILLION.toLocaleString()} Map set`, () => {
const hm = new Map<number, number>();
for (let i = 0; i < MILLION; i++) hm.set(i, i);
});
suite.add(`${MILLION.toLocaleString()} Set add`, () => {
const hs = new Set<number>();
for (let i = 0; i < MILLION; i++) hs.add(i);
});
suite.add(`${MILLION.toLocaleString()} set & get`, () => {

@@ -38,2 +52,3 @@ const hm = new HashMap<number, number>();

});
if (isCompetitor) {

@@ -51,2 +66,62 @@ suite.add(`${MILLION.toLocaleString()} CPT set & get`, () => {

}
suite.add(`${MILLION.toLocaleString()} Map set & get`, () => {
const hm = new Map<number, number>();
for (let i = 0; i < MILLION; i++) {
hm.set(i, i);
}
for (let i = 0; i < MILLION; i++) {
hm.get(i);
}
});
suite.add(`${MILLION.toLocaleString()} Set add & has`, () => {
const hs = new Set<number>();
for (let i = 0; i < MILLION; i++) hs.add(i);
for (let i = 0; i < MILLION; i++) hs.has(i);
});
suite.add(`${MILLION.toLocaleString()} ObjKey set & get`, () => {
const hm = new HashMap<[number, number], number>();
const objKeys:[number, number][] = [];
for (let i = 0; i < MILLION; i++) {
const obj: [number, number] = [i, i];
objKeys.push(obj)
hm.set(obj, i);
}
for (let i = 0; i < MILLION; i++) {
hm.get(objKeys[i]);
}
});
suite.add(`${MILLION.toLocaleString()} Map ObjKey set & get`, () => {
const hm = new Map<[number, number], number>();
const objs:[number, number][] = [];
for (let i = 0; i < MILLION; i++) {
const obj: [number, number] = [i, i];
objs.push(obj)
hm.set(obj, i);
}
for (let i = 0; i < MILLION; i++) {
hm.get(objs[i]);
}
});
suite.add(`${MILLION.toLocaleString()} Set ObjKey add & has`, () => {
const hs = new Set<[number, number]>();
const objs:[number, number][] = [];
for (let i = 0; i < MILLION; i++) {
const obj: [number, number] = [i, i];
objs.push(obj)
hs.add(obj);
}
for (let i = 0; i < MILLION; i++) {
hs.has(objs[i]);
}
});
export { suite };

@@ -232,1 +232,33 @@ import { HashMap } from '../../../../src';

});
describe('HashMap for coordinate object keys', () => {
const hashMap: HashMap<[number, number], number> = new HashMap();
const codObjs: [number, number][] = [];
test('set elements in hash map', () => {
for (let i = 0; i < 1000; i++) {
const codObj: [number, number] = [getRandomInt(-10000, 10000), i];
codObjs.push(codObj);
hashMap.set(codObj, i);
}
});
test('get elements in hash map', () => {
for (let i = 0; i < 1000; i++) {
const codObj = codObjs[i];
if (codObj) {
expect(hashMap.get(codObj)).toBe(i);
}
}
});
test('delete elements in hash map', () => {
for (let i = 0; i < 1000; i++) {
if (i === 500) expect(hashMap.size).toBe(500)
const codObj = codObjs[i];
if (codObj) hashMap.delete(codObj);
}
expect(hashMap.size).toBe(0);
});
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc