@rimbu/hashed
Version:
Immutable HashMap and HashSet implementations for TypeScript
389 lines • 16 kB
JavaScript
"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