@keyv/bigmap
Version:
Bigmap for Keyv
227 lines (226 loc) • 7 kB
JavaScript
// src/index.ts
import { Hookified } from "hookified";
function defaultHashFunction(key, storeSize) {
return djb2Hash(key, 0, storeSize - 1);
}
function djb2Hash(string_, min = 0, max = 10) {
let hash = 5381;
for (let i = 0; i < string_.length; i++) {
hash = hash * 33 ^ string_.charCodeAt(i);
}
const range = max - min + 1;
return min + Math.abs(hash) % range;
}
var BigMap = class extends Hookified {
_storeSize = 4;
_store = Array.from({ length: this._storeSize }, () => /* @__PURE__ */ new Map());
_storeHashFunction;
/**
* Creates an instance of BigMap.
* @param {BigMapOptions<K, V>} [options] - Optional configuration options for the BigMap.
*/
constructor(options) {
super(options);
if (options?.storeSize !== void 0) {
if (options.storeSize < 1) {
throw new Error("Store size must be at least 1.");
}
this.storeSize = options.storeSize;
}
this.initStore();
this._storeHashFunction = options?.storeHashFunction ?? defaultHashFunction;
}
/**
* Gets the number of maps in the store.
* @returns {number} The number of maps in the store.
*/
get storeSize() {
return this._storeSize;
}
/**
* Sets the number of maps in the store. If the size is less than 1, an error is thrown.
* If you change the store size it will clear all entries.
* @param {number} size - The new size of the store.
* @throws {Error} If the size is less than 1.
*/
set storeSize(size) {
if (size < 1) {
throw new Error("Store size must be at least 1.");
}
this._storeSize = size;
this.clear();
this.initStore();
}
/**
* Gets the hash function used for storing keys.
* @returns {StoreHashFunction | undefined} The hash function used for storing keys, or undefined if not set.
*/
get storeHashFunction() {
return this._storeHashFunction;
}
/**
* Sets the hash function used for storing keys.
* @param {StoreHashFunction} hashFunction - The hash function to use for storing keys.
*/
set storeHashFunction(hashFunction) {
this._storeHashFunction = hashFunction ?? defaultHashFunction;
}
/**
* Gets the store, which is an array of maps.
* @returns {Array<Map<K, V>>} The array of maps in the store.
*/
get store() {
return this._store;
}
/**
* Gets the map at the specified index in the store.
* @param {number} index - The index of the map to retrieve.
* @returns {Map<K, V>} The map at the specified index.
*/
getStoreMap(index) {
if (index < 0 || index >= this._storeSize) {
throw new Error(`Index out of bounds: ${index}. Valid range is 0 to ${this._storeSize - 1}.`);
}
return this._store[index];
}
/**
* Initializes the store with empty maps.
* This method is called when the BigMap instance is created.
*/
initStore() {
this._store = Array.from({ length: this._storeSize }, () => /* @__PURE__ */ new Map());
}
/**
* Gets the store for a specific key.
* The store is determined by applying the hash function to the key and the store size.
* If the hash function is not set, it defaults to using the default hash function.
* @param key - The key for which to get the store.
* @returns The store for the specified key.
*/
getStore(key) {
if (this._storeSize === 1) {
return this.getStoreMap(0);
}
const storeSize = this._storeSize - 1;
const index = this._storeHashFunction ? this._storeHashFunction(String(key), storeSize) : defaultHashFunction(String(key), storeSize);
return this.getStoreMap(index);
}
/**
* Returns an iterable of key-value pairs in the map.
* @returns {IterableIterator<[K, V]>} An iterable of key-value pairs in the map.
*/
entries() {
const entries = [];
for (const store of this._store) {
store.forEach((value, key) => entries.push([key, value]));
}
return entries[Symbol.iterator]();
}
/**
* Returns an iterable of keys in the map.
* @returns {IterableIterator<K>} An iterable of keys in the map.
*/
keys() {
const keys = [];
for (const store of this._store) {
store.forEach((_, key) => keys.push(key));
}
return keys[Symbol.iterator]();
}
/**
* Returns an iterable of values in the map.
* @returns {IterableIterator<V>} An iterable of values in the map.
*/
values() {
const values = [];
for (const store of this._store) {
store.forEach((value) => values.push(value));
}
return values[Symbol.iterator]();
}
/**
* Returns an iterator that iterates over the key-value pairs in the map.
* @returns {IterableIterator<[K, V]>} An iterator that iterates over the key-value pairs in the map.
*/
[Symbol.iterator]() {
const entries = [];
for (const store of this._store) {
store.forEach((value, key) => entries.push([key, value]));
}
return entries[Symbol.iterator]();
}
/**
* Clears all entries in the map.
* @returns {void} This method does not return a value.
*/
clear() {
for (const store of this._store) {
store.clear();
}
}
/**
* Deletes a key-value pair from the map.
* @param {K} key - The key of the entry to delete.
* @returns {boolean} Returns true if the entry was deleted, false if the key was not found.
*/
delete(key) {
const store = this.getStore(key);
const deleted = store.delete(key);
return deleted;
}
/**
* Calls a provided callback function once for each key-value pair in the map.
* @param {function} callbackfn - The function to execute for each key-value pair.
* @param {any} [thisArg] - An optional value to use as `this` when executing the callback.
*/
forEach(callbackfn, thisArg) {
this._store.forEach((store) => {
store.forEach(callbackfn, thisArg);
});
}
/**
* Gets the value associated with the specified key.
* @param {K} key - The key of the entry to get.
* @returns {V | undefined} The value associated with the key, or undefined if the key does not exist.
*/
get(key) {
const store = this.getStore(key);
return store.get(key);
}
/**
* Checks if the map contains a key.
* @param {K} key - The key to check for existence.
* @returns {boolean} Returns true if the key exists, false otherwise.
*/
has(key) {
const store = this.getStore(key);
return store.has(key);
}
/**
* Sets the value for a key in the map.
* @param {K} key - The key of the entry to set.
* @param {V} value - The value to set for the entry.
* @returns {Map<K, V>} The map instance.
*/
set(key, value) {
const store = this.getStore(key);
store.set(key, value);
return store;
}
/**
* Gets the number of entries in the map.
* @returns {number} The number of entries in the map.
*/
get size() {
let size = 0;
for (const store of this._store) {
size += store.size;
}
return size;
}
};
export {
BigMap,
defaultHashFunction,
djb2Hash
};