UNPKG

graph-builder

Version:

A graph builder library for modeling abstract graph structures.

227 lines 8.74 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const ImmutableSet_1 = require("../collect/ImmutableSet"); const ImmutableMap_1 = require("../collect/ImmutableMap"); // @todo: assertion lib const checkNonNegative = (n) => { if (n < 0) throw new Error('Negative number'); }; const checkPositive = (n) => { if (n <= 0) throw new Error('Non positive number'); }; const checkState = (assert) => { if (!assert) { throw new Error('Invalid state'); } }; /* * Copyright (C) 2016 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Modifications (C) 2019 Ben Sorohan */ const PRED = Symbol('PRED'); /** * An implementation of {@link GraphConnections} for directed graphs. */ class DirectedGraphConnections { // Every value in adjacentNodeValues this map must either be an instance of PredAndSucc with a successorValue of // type V, PRED (representing predecessor), or an instance of type V (representing successor). constructor(adjacentNodeValues, predecessorCount, successorCount) { this.adjacentNodeValues = adjacentNodeValues; this.predecessorCount = predecessorCount; this.successorCount = successorCount; checkState(predecessorCount <= adjacentNodeValues.size && successorCount <= adjacentNodeValues.size); } static of() { return new DirectedGraphConnections(new Map(), 0, 0); } static ofImmutable(predecessors, successorValues) { const adjacentNodeValues = new Map(successorValues); for (const predecessor of predecessors) { const value = successorValues.get(predecessor); // or should be from adjacentNodeValues? adjacentNodeValues.set(predecessor, PRED); if (value !== undefined) { adjacentNodeValues.set(predecessor, new PredAndSucc(value)); } } return new DirectedGraphConnections(ImmutableMap_1.ImmutableMap.copyOf(adjacentNodeValues), predecessors.size, successorValues.size); } adjacentNodes() { return ImmutableSet_1.ImmutableSet.fromIterable(this.adjacentNodeValues.keys()); } predecessors() { const that = this; return ImmutableSet_1.ImmutableSet.fromSetOperations({ [Symbol.iterator]: () => { const entries = that.adjacentNodeValues.entries(); const next = () => { let result = entries.next(); while (!result.done) { const [key, value] = result.value; if (DirectedGraphConnections.isPredecessor(value)) { return { value: key, done: false, }; } result = entries.next(); } return { value: undefined, done: true, }; }; const iterableIterator = { [Symbol.iterator]: () => iterableIterator, next, }; return iterableIterator; }, size: () => that.predecessorCount, has: (n) => { const value = that.adjacentNodeValues.get(n); return value !== undefined && DirectedGraphConnections.isPredecessor(value); }, }); } successors() { const that = this; return ImmutableSet_1.ImmutableSet.fromSetOperations({ [Symbol.iterator]: () => { const entries = that.adjacentNodeValues.entries(); const next = () => { let result = entries.next(); while (!result.done) { const [key, value] = result.value; if (DirectedGraphConnections.isSuccessor(value)) { return { value: key, done: false, }; } result = entries.next(); } return { value: undefined, done: true, }; }; const iterableIterator = { [Symbol.iterator]: () => iterableIterator, next, }; return iterableIterator; }, size: () => that.successorCount, has: (n) => { const value = that.adjacentNodeValues.get(n); return value !== undefined && DirectedGraphConnections.isSuccessor(value); }, }); } value(node) { const value = this.adjacentNodeValues.get(node); if (value == PRED) { return undefined; } if (value instanceof PredAndSucc) { return value.successorValue; } return value; } removePredecessor(node) { const previousValue = this.adjacentNodeValues.get(node); if (previousValue == PRED) { this.adjacentNodeValues.delete(node); checkNonNegative(--this.predecessorCount); } else if (previousValue instanceof PredAndSucc) { this.adjacentNodeValues.set(node, previousValue.successorValue); checkNonNegative(--this.predecessorCount); } } removeSuccessor(node) { const previousValue = this.adjacentNodeValues.get(node); if (previousValue === undefined || previousValue == PRED) { return undefined; } else if (previousValue instanceof PredAndSucc) { this.adjacentNodeValues.set(node, PRED); checkNonNegative(--this.successorCount); return previousValue.successorValue; } else { // successor this.adjacentNodeValues.delete(node); checkNonNegative(--this.successorCount); return previousValue; } } addPredecessor(node, unused) { const previousValue = this.adjacentNodeValues.get(node); this.adjacentNodeValues.set(node, PRED); if (previousValue === undefined) { checkPositive(++this.predecessorCount); } else if (previousValue instanceof PredAndSucc) { // Restore previous PredAndSucc. this.adjacentNodeValues.set(node, previousValue); } else if (previousValue !== PRED) { // successor // Do NOT use method parameter value 'unused'. In directed graphs, successors store the value. this.adjacentNodeValues.set(node, new PredAndSucc(previousValue)); checkPositive(++this.predecessorCount); } } addSuccessor(node, value) { const previousValue = this.adjacentNodeValues.get(node); this.adjacentNodeValues.set(node, value); if (previousValue === undefined) { checkPositive(++this.successorCount); return undefined; } else if (previousValue instanceof PredAndSucc) { this.adjacentNodeValues.set(node, new PredAndSucc(value)); return previousValue.successorValue; } else if (previousValue === PRED) { this.adjacentNodeValues.set(node, new PredAndSucc(value)); checkPositive(++this.successorCount); return undefined; } else { // successor return previousValue; } } static isPredecessor(value) { return (value == PRED) || (value instanceof PredAndSucc); } static isSuccessor(value) { return (value != PRED) && (value !== undefined); } } exports.DirectedGraphConnections = DirectedGraphConnections; /** * A wrapper class to indicate a node is both a predecessor and successor while still providing * the successor value. */ class PredAndSucc { constructor(successorValue) { this.successorValue = successorValue; } } //# sourceMappingURL=DirectedGraphConnections.js.map