Skip to content

Commit

Permalink
Add graph that can store edge weights
Browse files Browse the repository at this point in the history
Add a content graph class that can store edge weights, rather than just node weights

Test Plan: yarn test

Pull Request: #329
  • Loading branch information
yamadapc committed Feb 5, 2025
1 parent 95e0798 commit c30a222
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// @flow strict-local

import {ContentGraph, type NodeId} from '@atlaspack/graph';
import nullthrows from 'nullthrows';

/**
* A `ContentGraph` that also stores weights on edges.
*
* @template N The type of the node weight.
* @template EW The type of the edge weight.
*/
export class EdgeContentGraph<N, EW> extends ContentGraph<N, number> {
#edgeWeights: Map<string, EW> = new Map();

clone(): EdgeContentGraph<N, EW> {
const newGraph: EdgeContentGraph<N, EW> = new EdgeContentGraph();
let nodeId = 0;
for (let node of this.nodes) {
const contentKey = this._nodeIdToContentKey.get(nodeId);
if (node == null) {
// Add null node to preserve node ids
// $FlowFixMe
newGraph.addNode(null);
} else if (contentKey == null) {
newGraph.addNode(node);
} else {
newGraph.addNodeByContentKey(contentKey, node);
}
nodeId += 1;
}
for (let edge of this.getAllEdges()) {
const weight = this.getEdgeWeight(edge.from, edge.to);
newGraph.addWeightedEdge(edge.from, edge.to, edge.type, weight);
}

if (this.rootNodeId != null) {
const rootNodeContentKey = this._nodeIdToContentKey.get(this.rootNodeId);
const newGraphRootNodeId = newGraph.getNodeIdByContentKey(
nullthrows(rootNodeContentKey),
);
newGraph.setRootNodeId(newGraphRootNodeId);
}

return newGraph;
}

addWeightedEdge(
from: NodeId,
to: NodeId,
type: number,
weight: EW | null,
): void {
this.addEdge(from, to, type);
if (weight != null) {
this.#edgeWeights.set([String(from), String(to)].join(','), weight);
}
}

getEdgeWeight(from: NodeId, to: NodeId): EW | null {
return this.#edgeWeights.get([String(from), String(to)].join(',')) ?? null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// @flow strict-local

import assert from 'assert';
import {EdgeContentGraph} from '../../src/DominatorBundler/EdgeContentGraph';

describe('EdgeContentGraph', () => {
describe('addWeightedEdge', () => {
it('creates an edge between two nodes', () => {
const graph = new EdgeContentGraph<string, number>();
const a = graph.addNode('a');
const b = graph.addNode('b');
const edgeType = 1;
const weight = 10;
graph.addWeightedEdge(a, b, edgeType, weight);
const ids = graph.getNodeIdsConnectedFrom(a);
assert.deepEqual(ids, [b]);
});

it('should add and get edge weights', () => {
const graph = new EdgeContentGraph<string, number>();
const a = graph.addNode('a');
const b = graph.addNode('b');
const c = graph.addNode('b');

const edgeType = 1;
const weight1 = 10;
const weight2 = 20;

graph.addWeightedEdge(a, b, edgeType, weight1);
graph.addWeightedEdge(b, c, edgeType, weight2);

assert.equal(graph.getEdgeWeight(a, b), weight1);
assert.equal(graph.getEdgeWeight(b, c), weight2);
});
});

describe('clone', () => {
it('clones the graph', () => {
const graph = new EdgeContentGraph<string, number>();
const a = graph.addNode('a');
const b = graph.addNode('b');
const c = graph.addNode('c');

const edgeType = 1;
const weight1 = 10;
const weight2 = 20;

graph.addWeightedEdge(a, b, edgeType, weight1);
graph.addWeightedEdge(b, c, edgeType, weight2);

const clonedGraph = graph.clone();
assert.deepEqual(clonedGraph.nodes, graph.nodes);
assert.deepEqual(clonedGraph.getAllEdges(), graph.getAllEdges());
assert.equal(clonedGraph.getEdgeWeight(a, b), weight1);
assert.equal(clonedGraph.getEdgeWeight(b, c), weight2);
});
});
});

0 comments on commit c30a222

Please sign in to comment.