voided-data
Version:
Proper DS for TS
97 lines (96 loc) • 3.53 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createHashTable = void 0;
const maybe_1 = require("../../monads/maybe");
const hash_1 = __importDefault(require("../../objects/hash"));
const equals_1 = __importDefault(require("../../objects/equals"));
const MIN_LOAD = 0.25;
const MAX_LOAD = 1;
const EXPANSION_FACTOR = 2;
const CONTRACTION_FACTOR = 0.5;
const MIN_CAPACITY = 32;
function createHashTable() {
let size = 0;
let capacity = MIN_CAPACITY;
let buckets = new Array(capacity).fill(null).map(() => []);
const iter = () => buckets.flatMap((bucket) => bucket.map(([k, v]) => [k, v]));
const load = () => size / capacity;
const _set = (key, value) => {
const _hash = (0, hash_1.default)(key) % capacity;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const _bucket = buckets[_hash];
const pair = _bucket.find(([k]) => (0, equals_1.default)(k, key));
if (!pair) {
_bucket.push([key, value]);
return true;
}
pair[1] = value;
return false;
};
const resize = () => {
const _load = load();
let newCapacity = capacity;
if (_load < MIN_LOAD) {
newCapacity = Math.max(capacity * CONTRACTION_FACTOR, MIN_CAPACITY);
}
if (_load > MAX_LOAD) {
newCapacity = capacity * EXPANSION_FACTOR;
}
if (newCapacity !== capacity) {
capacity = newCapacity;
const oldBuckets = buckets;
buckets = new Array(capacity).fill(null).map(() => []);
oldBuckets.forEach((bucket) => bucket.forEach(([k, v]) => _set(k, v)));
}
};
return {
size: () => size,
set(key, value) {
if (_set(key, value)) {
size++;
resize();
}
},
iter,
get(key) {
const _hash = (0, hash_1.default)(key) % capacity;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const _bucket = buckets[_hash];
const pair = _bucket.find(([k]) => (0, equals_1.default)(k, key));
if (!pair) {
return (0, maybe_1.none)();
}
return (0, maybe_1.some)(pair[1]);
},
unset(key) {
const _hash = (0, hash_1.default)(key) % capacity;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const _bucket = buckets[_hash];
const _newBucket = _bucket.filter(([k]) => !(0, equals_1.default)(k, key));
buckets[_hash] = _newBucket;
if (_newBucket.length !== _bucket.length) {
size--;
resize();
}
},
map(mapper) {
const newMap = createHashTable();
iter().forEach((pair) => {
const [nk, nv] = mapper(pair);
newMap.set(nk, nv);
});
return newMap;
},
toString() {
return ('{ ' +
iter()
.map((pair) => JSON.stringify(pair))
.join(',') +
' }');
},
};
}
exports.createHashTable = createHashTable;