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