UNPKG

@rimbu/graph

Version:

Immutable Graph data structures for TypeScript

353 lines 14.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ValuedGraphBuilder = void 0; var tslib_1 = require("tslib"); var base_1 = require("@rimbu/base"); var common_1 = require("@rimbu/common"); var stream_1 = require("@rimbu/stream"); var index_cjs_1 = require("../../common/index.cjs"); var ValuedGraphBuilder = /** @class */ (function () { function ValuedGraphBuilder(isDirected, context, source) { var _this = this; this.isDirected = isDirected; this.context = context; this.source = source; this.connectionSize = 0; this._lock = 0; // prettier-ignore this.hasNode = function (node) { if (_this.source) return _this.source.hasNode(node); return _this.linkMap.hasKey(node); }; // prettier-ignore this.hasConnection = function (node1, node2) { var _a; if (_this.source) return _this.source.hasConnection(node1, node2); var targets = _this.linkMap.get(node1); return (_a = targets === null || targets === void 0 ? void 0 : targets.hasKey(node2)) !== null && _a !== void 0 ? _a : false; }; this.getValue = function (node1, node2, otherwise) { if (undefined !== _this.source) { return _this.source.getValue(node1, node2, otherwise); } var targets = _this.linkMap.get(node1); if (undefined === targets) return (0, common_1.OptLazy)(otherwise); return targets.get(node2, otherwise); }; this.addNodeInternal = function (node) { var changed = _this.linkMap.modifyAt(node, { ifNew: _this.context.linkConnectionsContext.builder, }); if (changed) _this.source = undefined; return changed; }; this.addNode = function (node) { _this.checkLock(); return _this.addNodeInternal(node); }; this.addNodes = function (nodes) { _this.checkLock(); return (stream_1.Stream.from(nodes).filterPure({ pred: _this.addNodeInternal }).count() > 0); }; // prettier-ignore this.removeNodeInternal = function (node) { var targets = _this.linkMap.removeKey(node); if (!targets) return false; _this.source = undefined; if (_this.isDirected) { _this.linkMap.forEach(function (_a) { var _b = tslib_1.__read(_a, 2), sourceNode = _b[0], targets = _b[1]; if (targets.removeKey(node)) { if (sourceNode !== node) _this.connectionSize--; } }); } else { _this.connectionSize -= targets.size; targets.forEach(function (_a) { var _b = tslib_1.__read(_a, 1), target = _b[0]; return _this.linkMap.updateAt(target, function (values) { values.removeKey(node); return values; }); }); } return true; }; // prettier-ignore this.removeNode = function (node) { _this.checkLock(); return _this.removeNodeInternal(node); }; // prettier-ignore this.removeNodes = function (nodes) { _this.checkLock(); return stream_1.Stream.from(nodes).filterPure({ pred: _this.removeNodeInternal }).count() > 0; }; this.connectInternal = function (node1, node2, value) { var changed = false; _this.linkMap.modifyAt(node1, { ifNew: function () { var targetBuilder = _this.context.linkConnectionsContext.builder(); targetBuilder.set(node2, value); _this.connectionSize++; changed = true; return targetBuilder; }, ifExists: function (targets) { var oldSize = targets.size; if (targets.set(node2, value)) { if (targets.size !== oldSize) _this.connectionSize++; changed = true; } return targets; }, }); if (changed) _this.source = undefined; if (changed && node1 !== node2) { _this.linkMap.modifyAt(node2, { ifNew: function () { var targetBuilder = _this.context.linkConnectionsContext.builder(); if (!_this.isDirected) targetBuilder.set(node1, value); return targetBuilder; }, ifExists: function (targets) { if (!_this.isDirected) targets.set(node1, value); return targets; }, }); } return changed; }; this.connect = function (node1, node2, value) { _this.checkLock(); return _this.connectInternal(node1, node2, value); }; this.connectAll = function (connections) { _this.checkLock(); return (stream_1.Stream.applyFilter(connections, { pred: _this.connectInternal, }).count() > 0); }; this.addGraphElement = function (element) { if (index_cjs_1.ValuedGraphElement.isLink(element)) { return _this.connectInternal(element[0], element[1], element[2]); } return _this.addNodeInternal(element[0]); }; this.addGraphElements = function (elements) { return (stream_1.Stream.from(elements).filterPure({ pred: _this.addGraphElement }).count() > 0); }; this.modifyAt = function (node1, node2, options) { _this.checkLock(); var preConnectionSize = _this.connectionSize; var changed = false; var addedOrUpdatedValue; _this.linkMap.modifyAt(node1, { ifNew: function (none) { if (undefined === options.ifNew) return none; var newValue = (0, common_1.OptLazyOr)(options.ifNew, none); if (none === newValue) return none; changed = true; addedOrUpdatedValue = newValue; _this.connectionSize++; var builder = _this.context.linkMapContext.builder(); builder.set(node2, newValue); return builder; }, ifExists: function (valueMap) { var ifExists = options.ifExists; if (undefined === ifExists) return valueMap; valueMap.modifyAt(node2, { ifNew: function (none) { if (undefined === options.ifNew) return none; var newValue = (0, common_1.OptLazyOr)(options.ifNew, none); if (none === newValue) return none; changed = true; addedOrUpdatedValue = newValue; _this.connectionSize++; return newValue; }, ifExists: function (currentValue, remove) { var newValue = ifExists instanceof Function ? ifExists(currentValue, remove) : ifExists; if (Object.is(newValue, currentValue)) return currentValue; changed = true; if (remove === newValue) { _this.connectionSize--; } else { addedOrUpdatedValue = newValue; } return newValue; }, }); return valueMap; }, }); if (!changed) return false; if (_this.isDirected) return true; // edge graph, need to update counterpart if (_this.connectionSize === preConnectionSize) { // value was updated _this.linkMap.modifyAt(node2, { ifNew: function () { var builder = _this.context.linkMapContext.builder(); builder.set(node1, addedOrUpdatedValue); return builder; }, ifExists: function (valueMap) { valueMap.set(node1, addedOrUpdatedValue); return valueMap; }, }); return true; } if (_this.connectionSize < preConnectionSize) { // value was removed _this.linkMap.modifyAt(node2, { ifExists: function (valueMap) { valueMap.removeKey(node1); return valueMap; }, }); return true; } // value was added _this.linkMap.modifyAt(node2, { ifNew: function () { var builder = _this.context.linkMapContext.builder(); builder.set(node1, addedOrUpdatedValue); return builder; }, ifExists: function (valueMap) { valueMap.set(node1, addedOrUpdatedValue); return valueMap; }, }); return true; }; // prettier-ignore this.disconnectInternal = function (node1, node2) { if (!_this.linkMap.context.isValidKey(node1) || !_this.linkMap.context.isValidKey(node2)) { return false; } var changed = false; var token = Symbol(); _this.linkMap.updateAt(node1, function (targets) { if (token !== targets.removeKey(node2, token)) { _this.connectionSize--; changed = true; } return targets; }); if (changed) _this.source = undefined; if (changed && node1 !== node2 && !_this.isDirected) { _this.linkMap.updateAt(node2, function (targets) { targets.removeKey(node1); return targets; }); } return changed; }; // prettier-ignore this.disconnect = function (node1, node2) { _this.checkLock(); return _this.disconnectInternal(node1, node2); }; // prettier-ignore this.disconnectAll = function (connections) { _this.checkLock(); return (stream_1.Stream.applyFilter(connections, { pred: _this.disconnectInternal }).count() > 0); }; this.build = function () { if (undefined !== _this.source) return _this.source; if (_this.isEmpty) return _this.context.empty(); var linkMap = _this.linkMap .buildMapValues(function (targets) { return targets.build(); }) .assumeNonEmpty(); return _this.context.createNonEmpty(linkMap, _this.connectionSize); }; // prettier-ignore this.buildMapValues = function (mapFun) { if (undefined !== _this.source) return _this.source.mapValues(mapFun); if (_this.isEmpty) return _this.context.empty(); var linkMap = _this.linkMap .buildMapValues(function (targets, source) { return targets.buildMapValues(function (value, target) { return mapFun(value, source, target); }); }) .assumeNonEmpty(); return _this.context.createNonEmpty(linkMap, _this.connectionSize); }; if (undefined !== source) this.connectionSize = source.connectionSize; } ValuedGraphBuilder.prototype.checkLock = function () { if (this._lock) base_1.RimbuError.throwModifiedBuilderWhileLoopingOverItError(); }; Object.defineProperty(ValuedGraphBuilder.prototype, "linkMap", { get: function () { if (undefined === this._linkMap) { if (undefined === this.source) { this._linkMap = this.context.linkMapContext.builder(); } else { this._linkMap = this.source.linkMap .mapValues(function (targets) { return targets.toBuilder(); }) .toBuilder(); } } return this._linkMap; }, enumerable: false, configurable: true }); Object.defineProperty(ValuedGraphBuilder.prototype, "isEmpty", { get: function () { if (this.source) return this.source.isEmpty; return this.linkMap.isEmpty; }, enumerable: false, configurable: true }); Object.defineProperty(ValuedGraphBuilder.prototype, "nodeSize", { get: function () { if (this.source) return this.source.nodeSize; return this.linkMap.size; }, enumerable: false, configurable: true }); return ValuedGraphBuilder; }()); exports.ValuedGraphBuilder = ValuedGraphBuilder; //# sourceMappingURL=builder.cjs.map