83 lines
1.8 KiB
JavaScript
83 lines
1.8 KiB
JavaScript
class Graph {
|
|
constructor() {
|
|
this.adj = new Map();
|
|
this[Graph._logSymbol] = [];
|
|
}
|
|
|
|
addNode(node) {
|
|
if (!this.adj.has(node)) {
|
|
this.adj.set(node, new Set());
|
|
}
|
|
}
|
|
|
|
addEdge(u, v) {
|
|
if (!this.adj.has(u)) this.adj.set(u, new Set());
|
|
if (!this.adj.has(v)) this.adj.set(v, new Set());
|
|
|
|
const uSet = this.adj.get(u);
|
|
const vSet = this.adj.get(v);
|
|
|
|
if (!uSet.has(v)) {
|
|
uSet.add(v);
|
|
vSet.add(u);
|
|
}
|
|
}
|
|
|
|
removeNode(node) {
|
|
if (!this.adj.has(node)) return;
|
|
for (const neighbor of this.adj.get(node)) {
|
|
this.adj.get(neighbor).delete(node);
|
|
}
|
|
this.adj.delete(node);
|
|
}
|
|
|
|
removeEdge(u, v) {
|
|
if (this.adj.has(u)) this.adj.get(u).delete(v);
|
|
if (this.adj.has(v)) this.adj.get(v).delete(u);
|
|
}
|
|
|
|
getNeighbors(node) {
|
|
return this.adj.has(node) ? Array.from(this.adj.get(node)) : [];
|
|
}
|
|
|
|
hasEdge(u, v) {
|
|
return this.adj.has(u) && this.adj.get(u).has(v);
|
|
}
|
|
|
|
getNodes() {
|
|
return Array.from(this.adj.keys());
|
|
}
|
|
|
|
getLog() {
|
|
return this[Graph._logSymbol].slice();
|
|
}
|
|
}
|
|
|
|
Graph._logSymbol = Symbol('log');
|
|
|
|
function createGraph() {
|
|
const graph = new Graph();
|
|
|
|
const handler = {
|
|
get(target, prop, receiver) {
|
|
const value = target[prop];
|
|
if (typeof value === 'function') {
|
|
// Mutating methods that should be logged
|
|
if (['addNode', 'addEdge', 'removeNode', 'removeEdge'].includes(prop)) {
|
|
return function (...args) {
|
|
const result = value.apply(target, args);
|
|
target[Graph._logSymbol].push({ method: prop, args });
|
|
return result;
|
|
};
|
|
}
|
|
// Non-mutating methods (including getLog)
|
|
return value.bind(target);
|
|
}
|
|
return value;
|
|
},
|
|
};
|
|
|
|
return new Proxy(graph, handler);
|
|
}
|
|
|
|
module.exports = { Graph, createGraph }; |