UNPKG

@rimbu/hashed

Version:

Immutable HashMap and HashSet implementations for TypeScript

389 lines 16 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.HashSetCollision = exports.HashSetBlock = exports.HashSetNonEmptyBase = exports.HashSetEmpty = void 0; var tslib_1 = require("tslib"); var base_1 = require("@rimbu/base"); var set_custom_1 = require("@rimbu/collection-types/set-custom"); var common_1 = require("@rimbu/common"); var stream_1 = require("@rimbu/stream"); var custom_1 = require("@rimbu/stream/custom"); var HashSetEmpty = /** @class */ (function (_super) { tslib_1.__extends(HashSetEmpty, _super); function HashSetEmpty(context) { var _this = _super.call(this) || this; _this.context = context; _this.addAll = context.from; return _this; } HashSetEmpty.prototype.has = function () { return false; }; HashSetEmpty.prototype.add = function (value) { return this.context.emptyBlock().add(value); }; HashSetEmpty.prototype.remove = function () { return this; }; HashSetEmpty.prototype.removeAll = function () { return this; }; HashSetEmpty.prototype.union = function (other) { if (this.context.isHashSetBlock(other) || this.context.isHashSetCollision(other)) { if (other.context === this.context) return other; } return this.context.from(other); }; HashSetEmpty.prototype.difference = function () { return this.context.empty(); }; HashSetEmpty.prototype.intersect = function () { return this.context.empty(); }; HashSetEmpty.prototype.symDifference = function (other) { return this.union(other); }; HashSetEmpty.prototype.toBuilder = function () { return this.context.builder(); }; HashSetEmpty.prototype.toString = function () { return "HashSet()"; }; HashSetEmpty.prototype.toJSON = function () { return { dataType: this.context.typeTag, value: [], }; }; return HashSetEmpty; }(set_custom_1.EmptyBase)); exports.HashSetEmpty = HashSetEmpty; var HashSetNonEmptyBase = /** @class */ (function (_super) { tslib_1.__extends(HashSetNonEmptyBase, _super); function HashSetNonEmptyBase() { return _super !== null && _super.apply(this, arguments) || this; } HashSetNonEmptyBase.prototype.asNormal = function () { return this; }; HashSetNonEmptyBase.prototype.addAll = function (values) { if ((0, custom_1.isEmptyStreamSourceInstance)(values)) return this; var builder = this.toBuilder(); builder.addAll(values); return builder.build(); }; HashSetNonEmptyBase.prototype.removeAll = function (values) { if ((0, custom_1.isEmptyStreamSourceInstance)(values)) return this; var builder = this.toBuilder(); builder.removeAll(values); return builder.build(); }; HashSetNonEmptyBase.prototype.filter = function (pred, options) { if (options === void 0) { options = {}; } var builder = this.context.builder(); builder.addAll(this.stream().filter(pred, options)); if (builder.size === this.size) return this; return builder.build(); }; HashSetNonEmptyBase.prototype.union = function (other) { if (other === this) return this; if ((0, custom_1.isEmptyStreamSourceInstance)(other)) return this; var builder = this.toBuilder(); builder.addAll(other); return builder.build().assumeNonEmpty(); }; HashSetNonEmptyBase.prototype.difference = function (other) { if (other === this) return this.context.empty(); if ((0, custom_1.isEmptyStreamSourceInstance)(other)) return this; var builder = this.toBuilder(); builder.removeAll(other); return builder.build(); }; HashSetNonEmptyBase.prototype.intersect = function (other) { if (other === this) return this; if ((0, custom_1.isEmptyStreamSourceInstance)(other)) return this.context.empty(); var builder = this.context.builder(); var it = stream_1.Stream.from(other)[Symbol.iterator](); var done = Symbol('Done'); var value; while (done !== (value = it.fastNext(done))) { if (this.has(value)) builder.add(value); } if (builder.size === this.size) return this; return builder.build(); }; HashSetNonEmptyBase.prototype.symDifference = function (other) { if (other === this) return this.context.empty(); if ((0, custom_1.isEmptyStreamSourceInstance)(other)) return this; var builder = this.toBuilder(); stream_1.Stream.from(other) .filterPure({ pred: builder.remove, negate: true }) .forEach(builder.add); return builder.build(); }; HashSetNonEmptyBase.prototype.toBuilder = function () { return this.context.createBuilder(this); }; HashSetNonEmptyBase.prototype.toString = function () { return this.stream().join({ start: 'HashSet(', sep: ', ', end: ')' }); }; HashSetNonEmptyBase.prototype.toJSON = function () { return { dataType: this.context.typeTag, value: [], }; }; return HashSetNonEmptyBase; }(set_custom_1.NonEmptyBase)); exports.HashSetNonEmptyBase = HashSetNonEmptyBase; var HashSetBlock = /** @class */ (function (_super) { tslib_1.__extends(HashSetBlock, _super); function HashSetBlock(context, entries, entrySets, size, level) { var _this = _super.call(this) || this; _this.context = context; _this.entries = entries; _this.entrySets = entrySets; _this.size = size; _this.level = level; return _this; } HashSetBlock.prototype.copy = function (entries, entrySets, size) { if (entries === void 0) { entries = this.entries; } if (entrySets === void 0) { entrySets = this.entrySets; } if (size === void 0) { size = this.size; } if (entries === this.entries && entrySets === this.entrySets && size === this.size) { return this; } return new HashSetBlock(this.context, entries, entrySets, size, this.level); }; HashSetBlock.prototype.stream = function () { if (null !== this.entries) { if (null === this.entrySets) { return stream_1.Stream.fromObjectValues(this.entries); } return stream_1.Stream.fromObjectValues(this.entries).concat(stream_1.Stream.fromObjectValues(this.entrySets).flatMap(function (entrySet) { return entrySet.stream(); })); } if (null === this.entrySets) { base_1.RimbuError.throwInvalidStateError(); } return stream_1.Stream.fromObjectValues(this.entrySets).flatMap(function (entrySet) { return entrySet.stream(); }); }; HashSetBlock.prototype.has = function (value, inHash) { if (!this.context.hasher.isValid(value)) return false; var hash = inHash !== null && inHash !== void 0 ? inHash : this.context.hash(value); var atKeyIndex = this.context.getKeyIndex(this.level, hash); if (null !== this.entries && atKeyIndex in this.entries) { var entry = this.entries[atKeyIndex]; return this.context.eq(entry, value); } if (null !== this.entrySets && atKeyIndex in this.entrySets) { var entrySet = this.entrySets[atKeyIndex]; return entrySet.has(value, hash); } return false; }; HashSetBlock.prototype.add = function (value, hash) { if (hash === void 0) { hash = this.context.hash(value); } var atKeyIndex = this.context.getKeyIndex(this.level, hash); if (null !== this.entries && atKeyIndex in this.entries) { var currentValue = this.entries[atKeyIndex]; if (this.context.eq(value, currentValue)) return this; var newEntries_1 = base_1.Arr.copySparse(this.entries); delete newEntries_1[atKeyIndex]; var isEmpty = true; /* eslint-disable @typescript-eslint/no-unused-vars */ for (var _ in newEntries_1) { isEmpty = false; break; } if (isEmpty) newEntries_1 = null; if (this.level < this.context.maxDepth) { var newEntrySet_1 = this.context .block(null, null, 0, this.level + 1) .add(currentValue) .add(value, hash); var newEntrySets_1 = null === this.entrySets ? [] : base_1.Arr.copySparse(this.entrySets); newEntrySets_1[atKeyIndex] = newEntrySet_1; return this.copy(newEntries_1, newEntrySets_1, this.size + 1); } var newEntrySet = this.context.collision(this.context.listContext.of(currentValue, value)); var newEntrySets = null === this.entrySets ? [] : base_1.Arr.copySparse(this.entrySets); newEntrySets[atKeyIndex] = newEntrySet; return this.copy(newEntries_1, newEntrySets, this.size + 1); } if (null !== this.entrySets && atKeyIndex in this.entrySets) { var currentEntrySet = this.entrySets[atKeyIndex]; var newEntrySet = currentEntrySet.add(value, hash); if (newEntrySet === currentEntrySet) return this; var newEntrySets = base_1.Arr.copySparse(this.entrySets); newEntrySets[atKeyIndex] = newEntrySet; return this.copy(undefined, newEntrySets, this.size + newEntrySet.size - currentEntrySet.size); } var newEntries = null === this.entries ? [] : base_1.Arr.copySparse(this.entries); newEntries[atKeyIndex] = value; return this.copy(newEntries, undefined, this.size + 1); }; HashSetBlock.prototype.remove = function (value, hash) { if (!this.context.hasher.isValid(value)) return this; var valueHash = hash !== null && hash !== void 0 ? hash : this.context.hash(value); var atKeyIndex = this.context.getKeyIndex(this.level, valueHash); if (null !== this.entries && atKeyIndex in this.entries) { var currentValue = this.entries[atKeyIndex]; if (!this.context.eq(currentValue, value)) return this; if (this.size === 1) return this.context.empty(); var newEntries = base_1.Arr.copySparse(this.entries); delete newEntries[atKeyIndex]; for (var _ in newEntries) { return this.copy(newEntries, undefined, this.size - 1); } return this.copy(null, undefined, this.size - 1); } if (null !== this.entrySets && atKeyIndex in this.entrySets) { // key is in entrySet var currentEntrySet = this.entrySets[atKeyIndex]; var newEntrySet = currentEntrySet.remove(value, hash); if (newEntrySet === currentEntrySet) return this; if (newEntrySet.size === 1) { var firstValue = undefined; if (this.context.isHashSetBlock(newEntrySet)) { for (var key in newEntrySet.entries) { firstValue = newEntrySet.entries[key]; break; } } else { firstValue = newEntrySet.entries.first(); } var newEntries = null === this.entries ? [] : base_1.Arr.copySparse(this.entries); newEntries[atKeyIndex] = firstValue; var newEntrySets_2 = base_1.Arr.copySparse(this.entrySets); delete newEntrySets_2[atKeyIndex]; return this.copy(newEntries, newEntrySets_2, this.size - 1); } var newEntrySets = base_1.Arr.copySparse(this.entrySets); newEntrySets[atKeyIndex] = newEntrySet; return this.copy(undefined, newEntrySets, this.size - currentEntrySet.size + newEntrySet.size); } return this; }; HashSetBlock.prototype.forEach = function (f, options) { if (options === void 0) { options = {}; } var _a = options.state, state = _a === void 0 ? (0, common_1.TraverseState)() : _a; if (state.halted) return; var halt = state.halt; if (null !== this.entries) { for (var key in this.entries) { f(this.entries[key], state.nextIndex(), halt); if (state.halted) return; } } if (null !== this.entrySets) { for (var key in this.entrySets) { this.entrySets[key].forEach(f, { state: state }); if (state.halted) return; } } }; HashSetBlock.prototype.toArray = function () { var result = []; if (null !== this.entries) { for (var key in this.entries) { result.push(this.entries[key]); } } if (null !== this.entrySets) { for (var key in this.entrySets) { result = result.concat(this.entrySets[key].toArray()); } } return result; }; return HashSetBlock; }(HashSetNonEmptyBase)); exports.HashSetBlock = HashSetBlock; var HashSetCollision = /** @class */ (function (_super) { tslib_1.__extends(HashSetCollision, _super); function HashSetCollision(context, entries) { var _this = _super.call(this) || this; _this.context = context; _this.entries = entries; return _this; } Object.defineProperty(HashSetCollision.prototype, "size", { get: function () { return this.entries.length; }, enumerable: false, configurable: true }); HashSetCollision.prototype.copy = function (entries) { if (entries === void 0) { entries = this.entries; } if (entries === this.entries) return this; return new HashSetCollision(this.context, entries); }; HashSetCollision.prototype.stream = function () { return this.entries.stream(); }; HashSetCollision.prototype.has = function (value, inHash) { if (!this.context.hasher.isValid(value)) return false; return this.stream().contains(value, { eq: this.context.eq }); }; HashSetCollision.prototype.add = function (value) { var currentIndex = this.stream().indexOf(value, { eq: this.context.eq }); if (undefined === currentIndex) { return this.copy(this.entries.append(value)); } return this.copy(this.entries.updateAt(currentIndex, value)); }; HashSetCollision.prototype.remove = function (value, hash) { if (!this.context.hasher.isValid(value)) return this; var currentIndex = this.stream().indexOf(value, { eq: this.context.eq }); if (undefined === currentIndex) return this; var newEntries = this.entries.remove(currentIndex).assumeNonEmpty(); return this.copy(newEntries); }; HashSetCollision.prototype.forEach = function (f, options) { if (options === void 0) { options = {}; } var _a = options.state, state = _a === void 0 ? (0, common_1.TraverseState)() : _a; if (state.halted) return; this.entries.forEach(f, { state: state }); }; HashSetCollision.prototype.toArray = function () { return this.entries.toArray(); }; return HashSetCollision; }(HashSetNonEmptyBase)); exports.HashSetCollision = HashSetCollision; //# sourceMappingURL=immutable.cjs.map