@rimbu/graph
Version:
Immutable Graph data structures for TypeScript
353 lines • 14.4 kB
JavaScript
"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