@rimbu/multimap
Version:
An immutable Map where each key can have multiple values
553 lines • 21.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MultiMapContext = exports.MultiMapBuilder = exports.MultiMapNonEmpty = exports.MultiMapEmpty = void 0;
var tslib_1 = require("tslib");
var base_1 = require("@rimbu/base");
var map_custom_1 = require("@rimbu/collection-types/map-custom");
var common_1 = require("@rimbu/common");
var stream_1 = require("@rimbu/stream");
var custom_1 = require("@rimbu/stream/custom");
var MultiMapEmpty = /** @class */ (function (_super) {
tslib_1.__extends(MultiMapEmpty, _super);
function MultiMapEmpty(context) {
var _this = _super.call(this) || this;
_this.context = context;
return _this;
}
Object.defineProperty(MultiMapEmpty.prototype, "keyMap", {
get: function () {
return this.context.keyMapContext.empty();
},
enumerable: false,
configurable: true
});
Object.defineProperty(MultiMapEmpty.prototype, "keySize", {
get: function () {
return 0;
},
enumerable: false,
configurable: true
});
MultiMapEmpty.prototype.streamKeys = function () {
return stream_1.Stream.empty();
};
MultiMapEmpty.prototype.streamValues = function () {
return stream_1.Stream.empty();
};
MultiMapEmpty.prototype.hasKey = function () {
return false;
};
MultiMapEmpty.prototype.hasEntry = function () {
return false;
};
MultiMapEmpty.prototype.add = function (key, value) {
var values = this.context.keyMapValuesContext.of(value);
var keyMap = this.context.keyMapContext.of([
key,
values,
]);
return this.context.createNonEmpty(keyMap, 1);
};
MultiMapEmpty.prototype.addEntries = function (entries) {
return this.context.from(entries);
};
MultiMapEmpty.prototype.getValues = function () {
return this.context.keyMapValuesContext.empty();
};
MultiMapEmpty.prototype.setValues = function (key, values) {
var valueSet = this.context.keyMapValuesContext.from(values);
if (!valueSet.nonEmpty())
return this;
var keyMap = this.context.keyMapContext.of([
key,
valueSet,
]);
return this.context.createNonEmpty(keyMap, valueSet.size);
};
MultiMapEmpty.prototype.modifyAt = function (atKey, options) {
if (undefined === options.ifNew)
return this;
return this.setValues(atKey, (0, common_1.OptLazy)(options.ifNew));
};
MultiMapEmpty.prototype.removeKey = function () {
return this;
};
MultiMapEmpty.prototype.removeKeys = function () {
return this;
};
MultiMapEmpty.prototype.removeKeyAndGet = function () {
return undefined;
};
MultiMapEmpty.prototype.removeEntry = function () {
return this;
};
MultiMapEmpty.prototype.removeEntries = function () {
return this;
};
MultiMapEmpty.prototype.toBuilder = function () {
return this.context.builder();
};
MultiMapEmpty.prototype.toString = function () {
return "".concat(this.context.typeTag, "()");
};
MultiMapEmpty.prototype.toJSON = function () {
return {
dataType: this.context.typeTag,
value: [],
};
};
return MultiMapEmpty;
}(map_custom_1.EmptyBase));
exports.MultiMapEmpty = MultiMapEmpty;
var MultiMapNonEmpty = /** @class */ (function (_super) {
tslib_1.__extends(MultiMapNonEmpty, _super);
function MultiMapNonEmpty(context, keyMap, size) {
var _this = _super.call(this) || this;
_this.context = context;
_this.keyMap = keyMap;
_this.size = size;
return _this;
}
MultiMapNonEmpty.prototype.assumeNonEmpty = function () {
return this;
};
MultiMapNonEmpty.prototype.asNormal = function () {
return this;
};
MultiMapNonEmpty.prototype.copy = function (keyMap, size) {
if (keyMap === this.keyMap)
return this;
return this.context.createNonEmpty(keyMap, size);
};
MultiMapNonEmpty.prototype.copyE = function (keyMap, size) {
if (keyMap.nonEmpty()) {
return this.copy(keyMap.assumeNonEmpty(), size);
}
return this.context.empty();
};
MultiMapNonEmpty.prototype.stream = function () {
return this.keyMap
.stream()
.flatMap(function (_a) {
var _b = tslib_1.__read(_a, 2), key = _b[0], values = _b[1];
return values.stream().map(function (v) { return [key, v]; });
});
};
MultiMapNonEmpty.prototype.streamKeys = function () {
return this.keyMap.streamKeys();
};
MultiMapNonEmpty.prototype.streamValues = function () {
return this.keyMap
.streamValues()
.flatMap(function (values) { return values.stream(); });
};
Object.defineProperty(MultiMapNonEmpty.prototype, "keySize", {
get: function () {
return this.keyMap.size;
},
enumerable: false,
configurable: true
});
MultiMapNonEmpty.prototype.hasKey = function (key) {
return this.keyMap.hasKey(key);
};
MultiMapNonEmpty.prototype.hasEntry = function (key, value) {
var _a;
var values = this.keyMap.get(key);
return (_a = values === null || values === void 0 ? void 0 : values.has(value)) !== null && _a !== void 0 ? _a : false;
};
MultiMapNonEmpty.prototype.getValues = function (key) {
return this.keyMap.get(key, this.context.keyMapValuesContext.empty());
};
MultiMapNonEmpty.prototype.add = function (key, value) {
var _this = this;
var newSize = this.size;
var newKeyMap = this.keyMap
.modifyAt(key, {
ifNew: function () {
newSize++;
return _this.context.keyMapValuesContext.of(value);
},
ifExists: function (values) {
var newValues = values.add(value);
if (newValues === values)
return values;
newSize -= values.size;
newSize += newValues.size;
return newValues;
},
})
.assumeNonEmpty();
return this.copy(newKeyMap, newSize);
};
MultiMapNonEmpty.prototype.addEntries = function (entries) {
if ((0, custom_1.isEmptyStreamSourceInstance)(entries))
return this;
var builder = this.toBuilder();
builder.addEntries(entries);
return builder.build().assumeNonEmpty();
};
MultiMapNonEmpty.prototype.setValues = function (key, values) {
return this.modifyAt(key, { ifNew: values, ifExists: function () { return values; } });
};
MultiMapNonEmpty.prototype.removeKey = function (key) {
if (!this.context.keyMapContext.isValidKey(key))
return this;
return this.modifyAt(key, { ifExists: function () { return []; } });
};
MultiMapNonEmpty.prototype.removeKeys = function (keys) {
if ((0, custom_1.isEmptyStreamSourceInstance)(keys))
return this;
var builder = this.toBuilder();
builder.removeKeys(keys);
return builder.build();
};
MultiMapNonEmpty.prototype.removeKeyAndGet = function (key) {
if (!this.context.keyMapContext.isValidKey(key))
return undefined;
var removed = undefined;
var result = this.modifyAt(key, {
ifExists: function (values) {
removed = values;
return [];
},
});
if (undefined === removed)
return undefined;
return [result, removed];
};
MultiMapNonEmpty.prototype.removeEntry = function (key, value) {
if (!this.context.keyMapContext.isValidKey(key))
return this;
return this.modifyAt(key, {
ifExists: function (values) { return values.remove(value); },
});
};
MultiMapNonEmpty.prototype.removeEntries = function (entries) {
if ((0, custom_1.isEmptyStreamSourceInstance)(entries))
return this;
var builder = this.toBuilder();
builder.removeEntries(entries);
return builder.build();
};
MultiMapNonEmpty.prototype.filter = function (pred, options) {
if (options === void 0) { options = {}; }
var builder = this.context.builder();
builder.addEntries(this.stream().filter(pred, options));
if (builder.size === this.size)
return this;
return builder.build();
};
MultiMapNonEmpty.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.stream().forEach(f, { state: state });
};
MultiMapNonEmpty.prototype.modifyAt = function (atKey, options) {
var _this = this;
var newSize = this.size;
var ifNew = options.ifNew, ifExists = options.ifExists;
var newKeyMap = this.keyMap.modifyAt(atKey, {
ifNew: function (none) {
if (undefined === ifNew)
return none;
var newValueStream = (0, common_1.OptLazy)(ifNew);
var newValues = _this.context.keyMapValuesContext.from(newValueStream);
if (!newValues.nonEmpty())
return none;
newSize += newValues.size;
return newValues;
},
ifExists: function (currentValues, remove) {
if (undefined === ifExists)
return currentValues;
var newValueStream = ifExists instanceof Function ? ifExists(currentValues) : ifExists;
var newValues = _this.context.keyMapValuesContext.from(newValueStream);
if (!newValues.nonEmpty()) {
newSize -= currentValues.size;
return remove;
}
newSize -= currentValues.size;
newSize += newValues.size;
return newValues;
},
});
return this.copyE(newKeyMap, newSize);
};
MultiMapNonEmpty.prototype.toArray = function () {
return this.stream().toArray();
};
MultiMapNonEmpty.prototype.toString = function () {
return this.keyMap.stream().join({
start: "".concat(this.context.typeTag, "("),
sep: ', ',
end: ')',
valueToString: function (_a) {
var _b = tslib_1.__read(_a, 2), key = _b[0], values = _b[1];
return "".concat(key, " -> ").concat(values.stream().join({ start: '[', sep: ', ', end: ']' }));
},
});
};
MultiMapNonEmpty.prototype.toJSON = function () {
return {
dataType: this.context.typeTag,
value: this.keyMap
.stream()
.map(function (entry) { return [entry[0], entry[1].toArray()]; })
.toArray(),
};
};
MultiMapNonEmpty.prototype.toBuilder = function () {
return this.context.createBuilder(this);
};
return MultiMapNonEmpty;
}(map_custom_1.NonEmptyBase));
exports.MultiMapNonEmpty = MultiMapNonEmpty;
var MultiMapBuilder = /** @class */ (function () {
function MultiMapBuilder(context, source) {
var _this = this;
this.context = context;
this.source = source;
this._lock = 0;
this._size = 0;
// prettier-ignore
this.getValues = function (key) {
var _a, _b, _c, _d;
return ((_d = (_b = (_a = _this.source) === null || _a === void 0 ? void 0 : _a.getValues(key)) !== null && _b !== void 0 ? _b : (_c = _this.keyMap.get(key)) === null || _c === void 0 ? void 0 : _c.build()) !== null && _d !== void 0 ? _d : _this.context.keyMapValuesContext.empty());
};
// prettier-ignore
this.hasKey = function (key) {
var _a, _b;
return (_b = (_a = _this.source) === null || _a === void 0 ? void 0 : _a.hasKey(key)) !== null && _b !== void 0 ? _b : _this.keyMap.hasKey(key);
};
// prettier-ignore
this.hasEntry = function (key, value) {
var _a, _b, _c, _d;
return ((_d = (_b = (_a = _this.source) === null || _a === void 0 ? void 0 : _a.hasEntry(key, value)) !== null && _b !== void 0 ? _b : (_c = _this.keyMap.get(key)) === null || _c === void 0 ? void 0 : _c.has(value)) !== null && _d !== void 0 ? _d : false);
};
this.add = function (key, value) {
_this.checkLock();
var changed = true;
_this.keyMap.modifyAt(key, {
ifNew: function () {
_this._size++;
var valueBuilder = _this.context.keyMapValuesContext.builder();
valueBuilder.add(value);
return valueBuilder;
},
ifExists: function (valueBuilder) {
_this._size -= valueBuilder.size;
changed = valueBuilder.add(value);
_this._size += valueBuilder.size;
return valueBuilder;
},
});
if (changed)
_this.source = undefined;
return changed;
};
this.addEntries = function (source) {
_this.checkLock();
return stream_1.Stream.applyFilter(source, { pred: _this.add }).count() > 0;
};
this.setValues = function (key, source) {
_this.checkLock();
var values = _this.context.keyMapValuesContext.from(source).toBuilder();
var size = values.size;
if (size <= 0)
return _this.removeKey(key);
return _this.keyMap.modifyAt(key, {
ifNew: function () {
_this._size += size;
_this.source = undefined;
return values;
},
ifExists: function (oldValues) {
_this._size -= oldValues.size;
_this._size += size;
_this.source = undefined;
return values;
},
});
};
this.removeEntry = function (key, value) {
_this.checkLock();
if (!_this.context.keyMapContext.isValidKey(key))
return false;
var changed = false;
_this.keyMap.modifyAt(key, {
ifExists: function (valueBuilder, remove) {
if (valueBuilder.remove(value)) {
_this._size--;
changed = true;
}
if (valueBuilder.size <= 0)
return remove;
return valueBuilder;
},
});
if (changed)
_this.source = undefined;
return changed;
};
this.removeEntries = function (entries) {
_this.checkLock();
return stream_1.Stream.applyFilter(entries, { pred: _this.removeEntry }).count() > 0;
};
// prettier-ignore
this.removeKey = function (key) {
_this.checkLock();
if (!_this.context.keyMapContext.isValidKey(key))
return false;
var changed = _this.keyMap.modifyAt(key, {
ifExists: function (valueBuilder, remove) {
_this._size -= valueBuilder.size;
return remove;
},
});
if (changed)
_this.source = undefined;
return changed;
};
// prettier-ignore
this.removeKeys = function (keys) {
_this.checkLock();
return stream_1.Stream.from(keys).filterPure({ pred: _this.removeKey }).count() > 0;
};
this.forEach = function (f, options) {
if (options === void 0) { options = {}; }
var _a = options.reversed, reversed = _a === void 0 ? false : _a, _b = options.state, state = _b === void 0 ? (0, common_1.TraverseState)() : _b;
if (state.halted)
return;
_this._lock++;
_this.keyMap.forEach(function (_a, _, outerHalt) {
var _b = tslib_1.__read(_a, 2), key = _b[0], values = _b[1];
values.forEach(function (value, index, halt) { return f([key, value], index, halt); }, {
reversed: reversed,
state: state,
});
if (state.halted)
outerHalt();
}, { reversed: reversed });
_this._lock--;
};
this.build = function () {
if (undefined !== _this.source)
return _this.source;
if (_this.isEmpty)
return _this.context.empty();
return _this.context.createNonEmpty(_this.keyMap
.buildMapValues(function (values) { return values.build().assumeNonEmpty(); })
.assumeNonEmpty(), _this.size);
};
if (undefined !== source)
this._size = source.size;
}
Object.defineProperty(MultiMapBuilder.prototype, "keyMap", {
get: function () {
if (undefined === this._keyMap) {
if (undefined === this.source) {
this._keyMap = this.context.keyMapContext.builder();
}
else {
this._keyMap = this.source.keyMap
.mapValues(function (v) { return v.toBuilder(); })
.toBuilder();
}
}
return this._keyMap;
},
enumerable: false,
configurable: true
});
MultiMapBuilder.prototype.checkLock = function () {
if (this._lock)
base_1.RimbuError.throwModifiedBuilderWhileLoopingOverItError();
};
Object.defineProperty(MultiMapBuilder.prototype, "size", {
get: function () {
return this._size;
},
enumerable: false,
configurable: true
});
Object.defineProperty(MultiMapBuilder.prototype, "isEmpty", {
get: function () {
return this.size === 0;
},
enumerable: false,
configurable: true
});
return MultiMapBuilder;
}());
exports.MultiMapBuilder = MultiMapBuilder;
var MultiMapContext = /** @class */ (function () {
function MultiMapContext(typeTag, keyMapContext, keyMapValuesContext) {
var _this = this;
this.typeTag = typeTag;
this.keyMapContext = keyMapContext;
this.keyMapValuesContext = keyMapValuesContext;
this._empty = Object.freeze(new MultiMapEmpty(this));
this.empty = function () {
return _this._empty;
};
this.from = function () {
var sources = [];
for (var _i = 0; _i < arguments.length; _i++) {
sources[_i] = arguments[_i];
}
var builder = _this.builder();
var i = -1;
var length = sources.length;
while (++i < length) {
var source = sources[i];
if ((0, custom_1.isEmptyStreamSourceInstance)(source))
continue;
if (builder.isEmpty &&
_this.isNonEmptyInstance(source) &&
source.context === _this) {
if (i === length - 1)
return source;
builder = source.toBuilder();
continue;
}
builder.addEntries(source);
}
return builder.build();
};
this.of = function () {
var entries = [];
for (var _i = 0; _i < arguments.length; _i++) {
entries[_i] = arguments[_i];
}
return _this.from(entries);
};
this.builder = function () {
return new MultiMapBuilder(_this);
};
this.reducer = function (source) {
return stream_1.Reducer.create(function () {
return undefined === source
? _this.builder()
: _this.from(source).toBuilder();
}, function (builder, entry) {
builder.add(entry[0], entry[1]);
return builder;
}, function (builder) { return builder.build(); });
};
}
MultiMapContext.prototype.isNonEmptyInstance = function (source) {
return source instanceof MultiMapNonEmpty;
};
MultiMapContext.prototype.createNonEmpty = function (keyMap, size) {
return new MultiMapNonEmpty(this, keyMap, size);
};
MultiMapContext.prototype.createBuilder = function (source) {
return new MultiMapBuilder(this, source);
};
return MultiMapContext;
}());
exports.MultiMapContext = MultiMapContext;
//# sourceMappingURL=base.cjs.map