graph-builder
Version:
A graph builder library for modeling abstract graph structures.
136 lines • 4.98 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/*
* 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
*/
/**
* An immutable pair representing the two endpoints of an edge in a graph. The {@link EndpointPair}
* of a directed edge is an ordered pair of nodes ({@link EndpointPair.source} and
* {@link EndpointPair.target}). The {@link EndpointPair} of an undirected edge is an
* unordered pair of nodes ({@link EndpointPair.nodeU} and {@link EndpointPair.nodeV}).
*
* The edge is a self-loop if, and only if, the two endpoints are equal.
*
* @public
*/
class EndpointPair {
constructor(nodeU, nodeV) {
this.nodeU = nodeU;
this.nodeV = nodeV;
}
/** Returns an {@link EndpointPair} representing the endpoints of a directed edge. */
static ordered(source, target) {
return new Ordered(source, target);
}
/** Returns an {@link EndpointPair} representing the endpoints of an undirected edge. */
static unordered(nodeU, nodeV) {
// Swap nodes on purpose to prevent callers from relying on the "ordering" of an unordered pair.
return new Unordered(nodeV, nodeU);
}
/** Returns an {@link EndpointPair} representing the endpoints of an edge in `graph`. */
static of(graph, nodeU, nodeV) {
return graph.isDirected() ? EndpointPair.ordered(nodeU, nodeV) : EndpointPair.unordered(nodeU, nodeV);
}
/**
* Returns the node that is adjacent to `node` along the origin edge.
*
* Throws an error if this {@link EndpointPair} does not contain `node`.
*/
adjacentNode(node) {
if (node === this.nodeU) {
return this.nodeV;
}
else if (node === this.nodeV) {
return this.nodeU;
}
else {
throw new Error("EndpointPair " + this + " does not contain node " + node);
}
}
/** Iterates in the order {@link EndpointPair.nodeU}, {@link EndpointPair.nodeV}. */
[Symbol.iterator]() {
return [this.nodeU, this.nodeV][Symbol.iterator]();
}
}
exports.EndpointPair = EndpointPair;
class Ordered extends EndpointPair {
source() {
return this.nodeU;
}
target() {
return this.nodeV;
}
isOrdered() {
return true;
}
equals(obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof EndpointPair)) {
return false;
}
const other = obj;
if (this.isOrdered() != other.isOrdered()) {
return false;
}
return this.source() === other.source() && this.target() === other.target();
}
toString() {
return "<" + this.source() + " -> " + this.target() + ">";
}
}
class Unordered extends EndpointPair {
source() {
throw new Error('NOT_AVAILABLE_ON_UNDIRECTED');
}
target() {
throw new Error(`NOT_AVAILABLE_ON_UNDIRECTED`);
}
isOrdered() {
return false;
}
equals(obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof EndpointPair)) {
return false;
}
const other = obj;
if (this.isOrdered() != other.isOrdered()) {
return false;
}
// Equivalent to the following simple implementation:
// boolean condition1 = nodeU().equals(other.nodeU()) && nodeV().equals(other.nodeV());
// boolean condition2 = nodeU().equals(other.nodeV()) && nodeV().equals(other.nodeU());
// return condition1 || condition2;
if (this.nodeU === other.nodeU) { // check condition1
// Here's the tricky bit. We don't have to explicitly check for condition2 in this case.
// Why? The second half of condition2 requires that nodeV equals other.nodeU.
// We already know that nodeU equals other.nodeU. Combined with the earlier statement,
// and the transitive property of equality, this implies that nodeU equals nodeV.
// If nodeU equals nodeV, condition1 == condition2, so checking condition1 is sufficient.
return this.nodeV === other.nodeV();
}
return this.nodeU === other.nodeV && this.nodeV === other.nodeU; // check condition2
}
toString() {
return "[" + this.nodeU + ", " + this.nodeV + "]";
}
}
//# sourceMappingURL=EndpointPair.js.map