UNPKG

@rimbu/hashed

Version:

Immutable HashMap and HashSet implementations for TypeScript

293 lines 11.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.HashSetCollisionBuilder = exports.HashSetBlockBuilder = void 0; var tslib_1 = require("tslib"); var base_1 = require("@rimbu/base"); var common_1 = require("@rimbu/common"); var list_1 = require("@rimbu/list"); var stream_1 = require("@rimbu/stream"); var common_2 = require("@rimbu/hashed/common"); var HashSetBlockBuilder = /** @class */ (function (_super) { tslib_1.__extends(HashSetBlockBuilder, _super); function HashSetBlockBuilder(context, source, _entries, _entrySets, size, level) { if (size === void 0) { size = (_a = source === null || source === void 0 ? void 0 : source.size) !== null && _a !== void 0 ? _a : 0; } if (level === void 0) { level = (_b = source === null || source === void 0 ? void 0 : source.level) !== null && _b !== void 0 ? _b : 0; } var _a, _b; var _this = _super.call(this) || this; _this.context = context; _this.source = source; _this._entries = _entries; _this._entrySets = _entrySets; _this.size = size; _this.level = level; _this._lock = 0; // prettier-ignore _this.has = function (value) { if (undefined !== _this.source) return _this.source.has(value); if (!_this.context.hasher.isValid(value)) return false; return _this.hasInternal(value); }; _this.add = function (value) { _this.checkLock(); return _this.addInternal(value); }; _this.addAll = function (source) { _this.checkLock(); return stream_1.Stream.from(source).filterPure({ pred: _this.add }).count() > 0; }; // prettier-ignore _this.remove = function (value) { _this.checkLock(); if (!_this.context.hasher.isValid(value)) return false; return _this.removeInternal(value); }; // prettier-ignore _this.removeAll = function (values) { _this.checkLock(); return stream_1.Stream.from(values).filterPure({ pred: _this.remove }).count() > 0; }; _this.forEach = function (f, options) { if (options === void 0) { options = {}; } var _a = options.state, state = _a === void 0 ? (0, common_1.TraverseState)() : _a; _this._lock++; _super.prototype.forEach.call(_this, f, { state: state }); _this._lock--; }; _this.build = function () { if (_this.size === 0) return _this.context.empty(); return _this.buildNE(); }; return _this; } HashSetBlockBuilder.prototype.checkLock = function () { if (this._lock) base_1.RimbuError.throwModifiedBuilderWhileLoopingOverItError(); }; HashSetBlockBuilder.prototype.prepareMutate = function () { var _this = this; if (undefined === this._entries) { if (undefined !== this.source) { this._entries = null === this.source.entries ? [] : base_1.Arr.copySparse(this.source.entries); } else { this._entries = []; } } if (undefined === this._entrySets) { if (undefined !== this.source && null !== this.source.entrySets) { this._entrySets = base_1.Arr.mapSparse(this.source.entrySets, function (entrySet) { if (_this.context.isHashSetBlock(entrySet)) { return new HashSetBlockBuilder(_this.context, entrySet); } return new HashSetCollisionBuilder(_this.context, entrySet); }); } else { this._entrySets = []; } } }; Object.defineProperty(HashSetBlockBuilder.prototype, "entries", { get: function () { this.prepareMutate(); return this._entries; }, enumerable: false, configurable: true }); Object.defineProperty(HashSetBlockBuilder.prototype, "entrySets", { get: function () { this.prepareMutate(); return this._entrySets; }, enumerable: false, configurable: true }); HashSetBlockBuilder.prototype.hasInternal = function (value, hash) { if (hash === void 0) { hash = this.context.hash(value); } if (undefined !== this.source) return this.source.has(value, hash); var keyIndex = this.context.getKeyIndex(this.level, hash); if (keyIndex in this.entries) { return this.context.eq(value, this.entries[keyIndex]); } if (keyIndex in this.entrySets) { var currentEntrySet = this.entrySets[keyIndex]; return currentEntrySet.hasInternal(value, hash); } return false; }; HashSetBlockBuilder.prototype.addInternal = function (value, hash) { if (hash === void 0) { hash = this.context.hash(value); } var keyIndex = this.context.getKeyIndex(this.level, hash); if (keyIndex in this.entries) { var currentEntry = this.entries[keyIndex]; if (this.context.eq(value, currentEntry)) return false; this.source = undefined; this.size++; delete this.entries[keyIndex]; if (this.level < this.context.maxDepth) { var newEntrySet_1 = new HashSetBlockBuilder(this.context, undefined, undefined, undefined, 0, this.level + 1); newEntrySet_1.addInternal(currentEntry); newEntrySet_1.addInternal(value, hash); this.entrySets[keyIndex] = newEntrySet_1; return true; } var newEntries = list_1.List.builder(); newEntries.append(currentEntry); newEntries.append(value); var newEntrySet = new HashSetCollisionBuilder(this.context, undefined, newEntries); this.entrySets[keyIndex] = newEntrySet; return true; } if (keyIndex in this.entrySets) { var currentEntrySet = this.entrySets[keyIndex]; var preSize = currentEntrySet.size; var changed = currentEntrySet.addInternal(value, hash); if (changed) this.source = undefined; this.size += currentEntrySet.size - preSize; return changed; } this.source = undefined; this.size++; this.entries[keyIndex] = value; return true; }; HashSetBlockBuilder.prototype.removeInternal = function (value, hash) { if (hash === void 0) { hash = this.context.hash(value); } var index = this.context.getKeyIndex(this.level, hash); if (index in this.entries) { // potential match in entries var currentValue = this.entries[index]; if (!this.context.eq(value, currentValue)) return false; // exact match this.source = undefined; this.size--; delete this.entries[index]; return true; } if (index in this.entrySets) { // potential match in entrysets var entrySet = this.entrySets[index]; var preSize = entrySet.size; if (!entrySet.removeInternal(value, hash)) { return false; } this.source = undefined; this.size += entrySet.size - preSize; if (entrySet.size > 1) return true; // single entry needs to be pulled up var first = undefined; if (this.context.isHashSetBlockBuilder(entrySet)) { for (var i in entrySet.entries) { first = entrySet.entries[i]; break; } } else { first = entrySet.entries.get(0, base_1.RimbuError.throwInvalidStateError); } delete this.entrySets[index]; // if the sparse emptySets array is empty, set it to an empty array var hasEntrySets = false; for (var _ in this.entrySets) { hasEntrySets = true; break; } if (!hasEntrySets) { this.entrySets.length = 0; } this.entries[index] = first; return true; } return false; }; HashSetBlockBuilder.prototype.buildNE = function () { if (undefined !== this.source) return this.source; var entries = this.entries.length === 0 ? null : base_1.Arr.copySparse(this.entries); var entrySets = this.entrySets.length === 0 ? null : base_1.Arr.mapSparse(this.entrySets, function (entrySet) { return entrySet.buildNE(); }); return this.context.block(entries, entrySets, this.size, this.level); }; return HashSetBlockBuilder; }(common_2.BlockBuilderBase)); exports.HashSetBlockBuilder = HashSetBlockBuilder; var HashSetCollisionBuilder = /** @class */ (function (_super) { tslib_1.__extends(HashSetCollisionBuilder, _super); function HashSetCollisionBuilder(context, source, _entries) { var _this = _super.call(this) || this; _this.context = context; _this.source = source; _this._entries = _entries; return _this; } HashSetCollisionBuilder.prototype.hasInternal = function (value, hash) { var _this = this; if (undefined !== this.source) return this.source.has(value, hash); var result = false; this.entries.forEach(function (v, _, halt) { if (_this.context.eq(v, value)) { result = true; halt(); } }); return result; }; HashSetCollisionBuilder.prototype.addInternal = function (value) { var _this = this; var index = -1; this.entries.forEach(function (v, i, halt) { if (_this.context.eq(v, value)) { index = i; halt(); } }); if (index < 0) { this.source = undefined; this.entries.append(value); return true; } var token = Symbol(); var oldValue = this.entries.set(index, value, token); var changed = token === oldValue || !this.context.eq(oldValue, value); if (changed) this.source = undefined; return changed; }; HashSetCollisionBuilder.prototype.removeInternal = function (value) { var _this = this; var index = -1; this.entries.forEach(function (v, i, halt) { if (_this.context.eq(v, value)) { index = i; halt(); } }); if (index < 0) return false; this.source = undefined; this.entries.remove(index); return true; }; HashSetCollisionBuilder.prototype.buildNE = function () { var _a; return ((_a = this.source) !== null && _a !== void 0 ? _a : this.context.collision(this.entries.build().assumeNonEmpty())); }; return HashSetCollisionBuilder; }(common_2.CollisionBuilderBase)); exports.HashSetCollisionBuilder = HashSetCollisionBuilder; //# sourceMappingURL=builder.cjs.map