@rimbu/multiset
Version:
An immutable Set where each element can occur multiple times
580 lines • 21.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MultiSetContext = exports.MultiSetBuilder = exports.MultiSetNonEmpty = exports.MultiSetEmpty = void 0;
var tslib_1 = require("tslib");
var base_1 = require("@rimbu/base");
var map_custom_1 = require("@rimbu/collection-types/map-custom");
var stream_1 = require("@rimbu/stream");
var custom_1 = require("@rimbu/stream/custom");
var common_1 = require("@rimbu/common");
var MultiSetEmpty = /** @class */ (function (_super) {
tslib_1.__extends(MultiSetEmpty, _super);
function MultiSetEmpty(context) {
var _this = _super.call(this) || this;
_this.context = context;
return _this;
}
MultiSetEmpty.prototype.add = function (elem, amount) {
if (undefined !== amount && amount <= 0)
return this;
var addAmount = amount !== null && amount !== void 0 ? amount : 1;
var countMap = this.context.countMapContext.of([
elem,
addAmount,
]);
return this.context.createNonEmpty(countMap, addAmount);
};
Object.defineProperty(MultiSetEmpty.prototype, "countMap", {
get: function () {
return this.context.countMapContext.empty();
},
enumerable: false,
configurable: true
});
Object.defineProperty(MultiSetEmpty.prototype, "sizeDistinct", {
get: function () {
return 0;
},
enumerable: false,
configurable: true
});
MultiSetEmpty.prototype.streamDistinct = function () {
return stream_1.Stream.empty();
};
MultiSetEmpty.prototype.addAll = function (values) {
return this.context.from(values);
};
MultiSetEmpty.prototype.addEntries = function (entries) {
if ((0, custom_1.isEmptyStreamSourceInstance)(entries))
return this;
var builder = this.toBuilder();
builder.addEntries(entries);
return builder.build();
};
MultiSetEmpty.prototype.remove = function () {
return this;
};
MultiSetEmpty.prototype.removeAllSingle = function () {
return this;
};
MultiSetEmpty.prototype.removeAllEvery = function () {
return this;
};
MultiSetEmpty.prototype.setCount = function (elem, amount) {
return this.add(elem, amount);
};
MultiSetEmpty.prototype.modifyCount = function (value, update) {
return this.add(value, update(0));
};
MultiSetEmpty.prototype.has = function () {
return false;
};
MultiSetEmpty.prototype.count = function () {
return 0;
};
MultiSetEmpty.prototype.forEach = function () {
//
};
MultiSetEmpty.prototype.filterEntries = function () {
return this;
};
MultiSetEmpty.prototype.toBuilder = function () {
return this.context.builder();
};
MultiSetEmpty.prototype.toArray = function () {
return [];
};
MultiSetEmpty.prototype.toString = function () {
return "".concat(this.context.typeTag, "()");
};
MultiSetEmpty.prototype.toJSON = function () {
return {
dataType: this.context.typeTag,
value: [],
};
};
return MultiSetEmpty;
}(map_custom_1.EmptyBase));
exports.MultiSetEmpty = MultiSetEmpty;
var MultiSetNonEmpty = /** @class */ (function (_super) {
tslib_1.__extends(MultiSetNonEmpty, _super);
function MultiSetNonEmpty(context, countMap, size) {
var _this = _super.call(this) || this;
_this.context = context;
_this.countMap = countMap;
_this.size = size;
return _this;
}
MultiSetNonEmpty.prototype.assumeNonEmpty = function () {
return this;
};
MultiSetNonEmpty.prototype.copy = function (countMap, size) {
if (countMap === this.countMap)
return this;
return this.context.createNonEmpty(countMap, size);
};
MultiSetNonEmpty.prototype.copyE = function (countMap, size) {
if (countMap.nonEmpty())
return this.copy(countMap, size);
return this.context.empty();
};
Object.defineProperty(MultiSetNonEmpty.prototype, "sizeDistinct", {
get: function () {
return this.countMap.size;
},
enumerable: false,
configurable: true
});
MultiSetNonEmpty.prototype.stream = function () {
return this.countMap
.stream()
.flatMap(function (_a) {
var _b = tslib_1.__read(_a, 2), value = _b[0], count = _b[1];
return stream_1.Stream.of(value).repeat(count);
});
};
MultiSetNonEmpty.prototype.streamDistinct = function () {
return this.countMap.streamKeys();
};
MultiSetNonEmpty.prototype.has = function (elem) {
return this.countMap.hasKey(elem);
};
MultiSetNonEmpty.prototype.count = function (elem) {
return this.countMap.get(elem, 0);
};
MultiSetNonEmpty.prototype.add = function (elem, amount) {
if (amount === void 0) { amount = 1; }
if (amount <= 0)
return this;
return this.copy(this.countMap
.modifyAt(elem, {
ifNew: amount,
ifExists: function (count) { return count + amount; },
})
.assumeNonEmpty(), this.size + amount);
};
MultiSetNonEmpty.prototype.addAll = function (values) {
if ((0, custom_1.isEmptyStreamSourceInstance)(values))
return this;
var builder = this.toBuilder();
builder.addAll(values);
return builder.build().assumeNonEmpty();
};
MultiSetNonEmpty.prototype.addEntries = function (entries) {
if ((0, custom_1.isEmptyStreamSourceInstance)(entries))
return this;
var builder = this.toBuilder();
builder.addEntries(entries);
return builder.build().assumeNonEmpty();
};
MultiSetNonEmpty.prototype.setCount = function (elem, amount) {
if (amount <= 0)
return this.remove(elem);
var sizeDelta = amount;
var newCountMap = this.countMap
.modifyAt(elem, {
ifNew: amount,
ifExists: function (count) {
sizeDelta -= count;
return amount;
},
})
.assumeNonEmpty();
return this.copyE(newCountMap, this.size + sizeDelta);
};
MultiSetNonEmpty.prototype.modifyCount = function (value, update) {
var sizeDelta = 0;
var newCountMap = this.countMap
.modifyAt(value, {
ifNew: function (none) {
var newAmount = update(0);
if (newAmount <= 0)
return none;
sizeDelta += newAmount;
return newAmount;
},
ifExists: function (amount, remove) {
sizeDelta -= amount;
var newAmount = update(amount);
if (newAmount <= 0)
return remove;
sizeDelta += newAmount;
return newAmount;
},
})
.assumeNonEmpty();
return this.copyE(newCountMap, this.size + sizeDelta);
};
MultiSetNonEmpty.prototype.remove = function (elem, options) {
if (options === void 0) { options = {}; }
var _a = options.amount, amount = _a === void 0 ? 1 : _a;
if (!this.context.isValidElem(elem))
return this;
var newSize = this.size;
var newCountMap = this.countMap.modifyAt(elem, {
ifExists: function (count, remove) {
if (amount === 'ALL') {
newSize -= count;
return remove;
}
var result = count - amount;
if (result <= 0) {
newSize -= count;
return remove;
}
newSize -= amount;
return result;
},
});
return this.copyE(newCountMap, newSize);
};
MultiSetNonEmpty.prototype.removeAllSingle = function (elems) {
if ((0, custom_1.isEmptyStreamSourceInstance)(elems))
return this;
var builder = this.toBuilder();
builder.removeAllSingle(elems);
return builder.build();
};
MultiSetNonEmpty.prototype.removeAllEvery = function (elems) {
if ((0, custom_1.isEmptyStreamSourceInstance)(elems))
return this;
var builder = this.toBuilder();
builder.removeAllEvery(elems);
return builder.build();
};
MultiSetNonEmpty.prototype.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;
var it = this.countMap.stream({ reversed: reversed })[Symbol.iterator]();
var entry;
var halt = state.halt;
while (!state.halted && undefined !== (entry = it.fastNext())) {
var value = entry[0];
var amount = entry[1];
while (!state.halted && --amount >= 0) {
f(value, state.nextIndex(), halt);
}
}
};
MultiSetNonEmpty.prototype.filterEntries = function (pred, options) {
if (options === void 0) { options = {}; }
var builder = this.context.builder();
stream_1.Stream.applyForEach(this.countMap.stream().filter(pred, options), builder.setCount);
if (builder.size === this.size)
return this;
return builder.build();
};
MultiSetNonEmpty.prototype.toArray = function () {
var result = [];
var it = this.countMap[Symbol.iterator]();
var entry;
while (undefined !== (entry = it.fastNext())) {
var amount = entry[1];
if (amount === 1)
result.push(entry[0]);
else {
var newArray = new Array(amount);
newArray.fill(entry[0]);
result = base_1.Arr.concat(result, newArray);
}
}
return result;
};
MultiSetNonEmpty.prototype.toString = function () {
return this.stream().join({
start: "".concat(this.context.typeTag, "("),
sep: ", ",
end: ")",
});
};
MultiSetNonEmpty.prototype.toJSON = function () {
return {
dataType: this.context.typeTag,
value: this.countMap.toArray(),
};
};
MultiSetNonEmpty.prototype.toBuilder = function () {
return new MultiSetBuilder(this.context, this);
};
return MultiSetNonEmpty;
}(map_custom_1.NonEmptyBase));
exports.MultiSetNonEmpty = MultiSetNonEmpty;
var MultiSetBuilder = /** @class */ (function () {
function MultiSetBuilder(context, source) {
var _this = this;
this.context = context;
this.source = source;
this._lock = 0;
this._size = 0;
// prettier-ignore
this.has = function (value) {
var _a, _b;
return (_b = (_a = _this.source) === null || _a === void 0 ? void 0 : _a.has(value)) !== null && _b !== void 0 ? _b : _this.countMap.hasKey(value);
};
this.add = function (value, amount) {
if (amount === void 0) { amount = 1; }
_this.checkLock();
if (amount <= 0)
return false;
_this._size += amount;
_this.countMap.modifyAt(value, {
ifNew: amount,
ifExists: function (count) { return count + amount; },
});
_this.source = undefined;
return true;
};
this.addAll = function (source) {
_this.checkLock();
return stream_1.Stream.from(source).filterPure({ pred: _this.add }, 1).count() > 0;
};
this.addEntries = function (entries) {
_this.checkLock();
return stream_1.Stream.applyFilter(entries, { pred: _this.add }).count() > 0;
};
// prettier-ignore
this.remove = function (value, amount) {
if (amount === void 0) { amount = 1; }
_this.checkLock();
if (typeof amount === 'number' && amount <= 0)
return 0;
if (!_this.context.isValidElem(value))
return 0;
var removed = 0;
_this.countMap.modifyAt(value, {
ifExists: function (count, remove) {
if (amount === 'ALL') {
removed = count;
return remove;
}
var result = count - amount;
if (result <= 0) {
removed = count;
return remove;
}
removed = amount;
return result;
},
});
_this._size -= removed;
if (removed > 0)
_this.source = undefined;
return removed;
};
this.setCount = function (value, amount) {
_this.checkLock();
if (amount <= 0) {
return _this.remove(value, 'ALL') > 0;
}
_this._size += amount;
var changed = _this.countMap.modifyAt(value, {
ifNew: amount,
ifExists: function (count) {
_this._size -= count;
return amount;
},
});
if (changed)
_this.source = undefined;
return changed;
};
this.modifyCount = function (value, update) {
_this.checkLock();
var changed = _this.countMap.modifyAt(value, {
ifNew: function (none) {
var newAmount = update(0);
if (newAmount <= 0)
return none;
_this._size += newAmount;
return newAmount;
},
ifExists: function (currentCount, remove) {
_this._size -= currentCount;
var newCount = update(currentCount);
if (newCount <= 0)
return remove;
_this._size += newCount;
return newCount;
},
});
if (changed)
_this.source = undefined;
return changed;
};
// prettier-ignore
this.count = function (value) {
var _a, _b;
return (_b = (_a = _this.source) === null || _a === void 0 ? void 0 : _a.count(value)) !== null && _b !== void 0 ? _b : _this.countMap.get(value, 0);
};
// prettier-ignore
this.removeAll = function (values, mode) {
_this.checkLock();
if ((0, custom_1.isEmptyStreamSourceInstance)(values))
return false;
return (stream_1.Stream.from(values)
.mapPure(_this.remove, mode === 'SINGLE' ? 1 : 'ALL')
.countElement(0, { negate: true }) > 0);
};
// prettier-ignore
this.removeAllSingle = function (values) {
return _this.removeAll(values, 'SINGLE');
};
// prettier-ignore
this.removeAllEvery = function (values) {
return _this.removeAll(values, 'ALL');
};
this.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._lock++;
var halt = state.halt;
_this.countMap.forEach(function (_a, _, builderHalt) {
var _b = tslib_1.__read(_a, 2), value = _b[0], amount = _b[1];
var time = 0;
while (!state.halted && time++ < amount) {
f(value, state.nextIndex(), halt);
}
if (state.halted)
builderHalt();
});
_this._lock--;
};
this.build = function () {
if (undefined !== _this.source)
return _this.source;
if (_this.isEmpty)
return _this.context.empty();
var newCountMap = _this.countMap
.build()
.assumeNonEmpty();
return new MultiSetNonEmpty(_this.context, newCountMap, _this.size);
};
if (undefined !== source)
this._size = source.size;
}
Object.defineProperty(MultiSetBuilder.prototype, "countMap", {
get: function () {
if (undefined === this._countMap) {
if (undefined === this.source) {
this._countMap = this.context.countMapContext.builder();
}
else {
this._countMap = this.source.countMap.toBuilder();
}
}
return this._countMap;
},
enumerable: false,
configurable: true
});
MultiSetBuilder.prototype.checkLock = function () {
if (this._lock)
base_1.RimbuError.throwModifiedBuilderWhileLoopingOverItError();
};
Object.defineProperty(MultiSetBuilder.prototype, "size", {
get: function () {
return this._size;
},
enumerable: false,
configurable: true
});
Object.defineProperty(MultiSetBuilder.prototype, "sizeDistinct", {
get: function () {
var _a, _b;
return (_b = (_a = this.source) === null || _a === void 0 ? void 0 : _a.sizeDistinct) !== null && _b !== void 0 ? _b : this.countMap.size;
},
enumerable: false,
configurable: true
});
Object.defineProperty(MultiSetBuilder.prototype, "isEmpty", {
get: function () {
return 0 === this.size;
},
enumerable: false,
configurable: true
});
return MultiSetBuilder;
}());
exports.MultiSetBuilder = MultiSetBuilder;
var MultiSetContext = /** @class */ (function () {
function MultiSetContext(typeTag, countMapContext) {
var _this = this;
this.typeTag = typeTag;
this.countMapContext = countMapContext;
this._empty = Object.freeze(new MultiSetEmpty(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.addAll(source);
}
return builder.build();
};
// prettier-ignore
this.of = function () {
var values = [];
for (var _i = 0; _i < arguments.length; _i++) {
values[_i] = arguments[_i];
}
return _this.from(values);
};
this.builder = function () {
return new MultiSetBuilder(_this);
};
this.reducer = function (source) {
return stream_1.Reducer.create(function () {
return undefined === source
? _this.builder()
: _this.from(source).toBuilder();
}, function (builder, value) {
builder.add(value);
return builder;
}, function (builder) { return builder.build(); });
};
}
Object.defineProperty(MultiSetContext.prototype, "_types", {
get: function () {
return undefined;
},
enumerable: false,
configurable: true
});
MultiSetContext.prototype.isValidElem = function (elem) {
return this.countMapContext.isValidKey(elem);
};
MultiSetContext.prototype.isNonEmptyInstance = function (source) {
return source instanceof MultiSetNonEmpty;
};
MultiSetContext.prototype.createNonEmpty = function (countMap, size) {
return new MultiSetNonEmpty(this, countMap, size);
};
MultiSetContext.prototype.createBuilder = function (source) {
return new MultiSetBuilder(this, source);
};
return MultiSetContext;
}());
exports.MultiSetContext = MultiSetContext;
//# sourceMappingURL=base.cjs.map