All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.javascript.jscomp.graph.LinkedDirectedGraph Maven / Gradle / Ivy

Go to download

Closure Compiler is a JavaScript optimizing compiler. It parses your JavaScript, analyzes it, removes dead code and rewrites and minimizes what's left. It also checks syntax, variable references, and types, and warns about common JavaScript pitfalls. It is used in many of Google's JavaScript apps, including Gmail, Google Web Search, Google Maps, and Google Docs. This binary checks for style issues such as incorrect or missing JSDoc usage, and missing goog.require() statements. It does not do more advanced checks such as typechecking.

There is a newer version: v20200830
Show newest version
/*
 * Copyright 2008 The Closure Compiler 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.
 */

package com.google.javascript.jscomp.graph;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * A directed graph using linked list within nodes to store edge information.
 * 

* This implementation favors directed graph operations inherited from * DirectedGraph. * Operations from Graph would tends to be slower. * * * @param Value type that the graph node stores. * @param Value type that the graph edge stores. */ public class LinkedDirectedGraph extends DiGraph implements GraphvizGraph { protected final Map> nodes = new LinkedHashMap<>(); @Override public SubGraph newSubGraph() { return new SimpleSubGraph<>(this); } public static LinkedDirectedGraph createWithoutAnnotations() { return new LinkedDirectedGraph<>(false, false); } public static LinkedDirectedGraph create() { return new LinkedDirectedGraph<>(true, true); } private final boolean useNodeAnnotations; private final boolean useEdgeAnnotations; protected LinkedDirectedGraph( boolean useNodeAnnotations, boolean useEdgeAnnotations) { this.useNodeAnnotations = useNodeAnnotations; this.useEdgeAnnotations = useEdgeAnnotations; } @Override public void connect(N srcValue, E edgeValue, N destValue) { LinkedDirectedGraphNode src = getNodeOrFail(srcValue); LinkedDirectedGraphNode dest = getNodeOrFail(destValue); LinkedDirectedGraphEdge edge = useEdgeAnnotations ? new AnnotatedLinkedDirectedGraphEdge<>(src, edgeValue, dest) : new LinkedDirectedGraphEdge<>(src, edgeValue, dest); src.getOutEdges().add(edge); dest.getInEdges().add(edge); } // TODO(johnlenz): make this part of the general graph interface. /** * DiGraphNode look ups can be expensive for a large graph operation, prefer this * method if you have the DiGraphNode available. */ public void connect( DiGraphNode src, E edgeValue, DiGraphNode dest) { LinkedDirectedGraphEdge edge = useEdgeAnnotations ? new AnnotatedLinkedDirectedGraphEdge<>(src, edgeValue, dest) : new LinkedDirectedGraphEdge<>(src, edgeValue, dest); src.getOutEdges().add(edge); dest.getInEdges().add(edge); } // TODO(johnlenz): make this part of the general graph interface. /** * DiGraphNode look ups can be expensive for a large graph operation, prefer this * method if you have the DiGraphNode available. */ public void connectIfNotConnectedInDirection(N srcValue, E edgeValue, N destValue) { LinkedDirectedGraphNode src = createDirectedGraphNode(srcValue); LinkedDirectedGraphNode dest = createDirectedGraphNode(destValue); if (!this.isConnectedInDirection(src, Predicates.equalTo(edgeValue), dest)) { this.connect(src, edgeValue, dest); } } @Override public void disconnect(N n1, N n2) { disconnectInDirection(n1, n2); disconnectInDirection(n2, n1); } @Override public void disconnectInDirection(N srcValue, N destValue) { LinkedDirectedGraphNode src = getNodeOrFail(srcValue); LinkedDirectedGraphNode dest = getNodeOrFail(destValue); for (DiGraphEdge edge : getDirectedGraphEdges(srcValue, destValue)) { src.getOutEdges().remove(edge); dest.getInEdges().remove(edge); } } @Override public Iterable> getDirectedGraphNodes() { return Collections.>unmodifiableCollection( nodes.values()); } @Override public DiGraphNode getDirectedGraphNode(N nodeValue) { return nodes.get(nodeValue); } @Override public GraphNode getNode(N nodeValue) { return getDirectedGraphNode(nodeValue); } @Override public List> getInEdges(N nodeValue) { LinkedDirectedGraphNode node = getNodeOrFail(nodeValue); return Collections.unmodifiableList(node.getInEdges()); } @Override public List> getOutEdges(N nodeValue) { LinkedDirectedGraphNode node = getNodeOrFail(nodeValue); return Collections.unmodifiableList(node.getOutEdges()); } @Override public LinkedDirectedGraphNode createDirectedGraphNode(N nodeValue) { LinkedDirectedGraphNode node = nodes.computeIfAbsent( nodeValue, (N k) -> useNodeAnnotations ? new AnnotatedLinkedDirectedGraphNode(k) : new LinkedDirectedGraphNode(k)); return node; } @Override public List> getEdges(N n1, N n2) { // Since this is a method from a generic graph, edges from both // directions must be added to the returning list. List> forwardEdges = getDirectedGraphEdges(n1, n2); List> backwardEdges = getDirectedGraphEdges(n2, n1); int totalSize = forwardEdges.size() + backwardEdges.size(); List> edges = new ArrayList<>(totalSize); edges.addAll(forwardEdges); edges.addAll(backwardEdges); return edges; } @Override public List> getEdges() { List> result = new ArrayList<>(); for (DiGraphNode node : nodes.values()) { result.addAll(node.getOutEdges()); } return Collections.unmodifiableList(result); } @Override public GraphEdge getFirstEdge(N n1, N n2) { DiGraphNode dNode1 = getNodeOrFail(n1); DiGraphNode dNode2 = getNodeOrFail(n2); for (DiGraphEdge outEdge : dNode1.getOutEdges()) { if (outEdge.getDestination() == dNode2) { return outEdge; } } for (DiGraphEdge outEdge : dNode2.getOutEdges()) { if (outEdge.getDestination() == dNode1) { return outEdge; } } return null; } @Override public DiGraphNode createNode(N value) { return createDirectedGraphNode(value); } @Override public List> getDirectedGraphEdges(N n1, N n2) { DiGraphNode dNode1 = getNodeOrFail(n1); DiGraphNode dNode2 = getNodeOrFail(n2); List> edges = new ArrayList<>(); for (DiGraphEdge outEdge : dNode1.getOutEdges()) { if (outEdge.getDestination() == dNode2) { edges.add(outEdge); } } return edges; } /** * DiGraphNode look ups can be expensive for a large graph operation, prefer the * version below that takes DiGraphNodes, if you have them available. */ @Override public boolean isConnectedInDirection(N n1, N n2) { return isConnectedInDirection(n1, Predicates.alwaysTrue(), n2); } /** * DiGraphNode look ups can be expensive for a large graph operation, prefer the * version below that takes DiGraphNodes, if you have them available. */ @Override public boolean isConnectedInDirection(N n1, E edgeValue, N n2) { return isConnectedInDirection(n1, Predicates.equalTo(edgeValue), n2); } /** * DiGraphNode look ups can be expensive for a large graph operation, prefer this * method if you have the DiGraphNodes available. */ public boolean isConnectedInDirection( DiGraphNode dNode1, Predicate edgeMatcher, DiGraphNode dNode2) { // Verify the nodes. List> outEdges = dNode1.getOutEdges(); int outEdgesLen = outEdges.size(); List> inEdges = dNode2.getInEdges(); int inEdgesLen = inEdges.size(); // It is possible that there is a large assymmetry between the nodes, so pick the direction // to search based on the shorter list since the edge lists should be symmetric. if (outEdgesLen < inEdgesLen) { for (int i = 0; i < outEdgesLen; i++) { DiGraphEdge outEdge = outEdges.get(i); if (outEdge.getDestination() == dNode2 && edgeMatcher.apply(outEdge.getValue())) { return true; } } } else { for (int i = 0; i < inEdgesLen; i++) { DiGraphEdge inEdge = inEdges.get(i); if (inEdge.getSource() == dNode1 && edgeMatcher.apply(inEdge.getValue())) { return true; } } } return false; } private boolean isConnectedInDirection(N n1, Predicate edgeMatcher, N n2) { // Verify the nodes. DiGraphNode dNode1 = getNodeOrFail(n1); DiGraphNode dNode2 = getNodeOrFail(n2); return isConnectedInDirection(dNode1, edgeMatcher, dNode2); } @Override public List> getDirectedPredNodes(N nodeValue) { return getDirectedPredNodes(nodes.get(nodeValue)); } @Override public List> getDirectedPredNodes(DiGraphNode dNode) { checkNotNull(dNode); List> nodeList = new ArrayList<>(dNode.getInEdges().size()); for (DiGraphEdge edge : dNode.getInEdges()) { nodeList.add(edge.getSource()); } return nodeList; } @Override public List> getDirectedSuccNodes(N nodeValue) { return getDirectedSuccNodes(nodes.get(nodeValue)); } @Override public List> getDirectedSuccNodes( DiGraphNode dNode) { checkNotNull(dNode); List> nodeList = new ArrayList<>(dNode.getOutEdges().size()); for (DiGraphEdge edge : dNode.getOutEdges()) { nodeList.add(edge.getDestination()); } return nodeList; } @Override public List getGraphvizEdges() { List edgeList = new ArrayList<>(); for (LinkedDirectedGraphNode node : nodes.values()) { for (DiGraphEdge edge : node.getOutEdges()) { edgeList.add((LinkedDirectedGraphEdge) edge); } } return edgeList; } @Override public List getGraphvizNodes() { List nodeList = new ArrayList<>(nodes.size()); for (LinkedDirectedGraphNode node : nodes.values()) { nodeList.add(node); } return nodeList; } @Override public String getName() { return "LinkedGraph"; } @Override public boolean isDirected() { return true; } @Override public Collection> getNodes() { return Collections.>unmodifiableCollection(nodes.values()); } @Override public int getNodeCount() { return nodes.size(); } @Override public List> getNeighborNodes(N value) { DiGraphNode node = getDirectedGraphNode(value); List> result = new ArrayList<>( node.getInEdges().size() + node.getOutEdges().size()); for (DiGraphEdge inEdge : node.getInEdges()) { result.add(inEdge.getSource()); } for (DiGraphEdge outEdge : node.getOutEdges()) { result.add(outEdge.getDestination()); } return result; } @Override public int getNodeDegree(N value) { DiGraphNode node = getNodeOrFail(value); return node.getInEdges().size() + node.getOutEdges().size(); } /** * A directed graph node that stores outgoing edges and incoming edges as an * list within the node itself. */ public static class LinkedDirectedGraphNode implements DiGraphNode, GraphvizNode { List> inEdgeList = new ArrayList<>(); List> outEdgeList = new ArrayList<>(); protected final N value; /** * Constructor * * @param nodeValue Node's value. */ LinkedDirectedGraphNode(N nodeValue) { this.value = nodeValue; } @Override public N getValue() { return value; } @Override public A getAnnotation() { throw new UnsupportedOperationException( "Graph initialized with node annotations turned off"); } @Override public void setAnnotation(Annotation data) { throw new UnsupportedOperationException( "Graph initialized with node annotations turned off"); } @Override public String getColor() { return "white"; } @Override public String getId() { return "LDN" + hashCode(); } @Override public String getLabel() { return String.valueOf(value); } @Override public String toString() { return getLabel(); } @Override public List> getInEdges() { return inEdgeList; } @Override public List> getOutEdges() { return outEdgeList; } } /** * A directed graph node with annotations. */ static class AnnotatedLinkedDirectedGraphNode extends LinkedDirectedGraphNode { protected Annotation annotation; /** * @param nodeValue Node's value. */ AnnotatedLinkedDirectedGraphNode(N nodeValue) { super(nodeValue); } @SuppressWarnings("unchecked") @Override public A getAnnotation() { return (A) annotation; } @Override public void setAnnotation(Annotation data) { annotation = data; } } /** * A directed graph edge that stores the source and destination nodes at each * edge. */ static class LinkedDirectedGraphEdge implements DiGraphEdge, GraphvizEdge { private DiGraphNode sourceNode; private DiGraphNode destNode; protected final E value; /** * Constructor. * * @param edgeValue Edge Value. */ LinkedDirectedGraphEdge(DiGraphNode sourceNode, E edgeValue, DiGraphNode destNode) { this.value = edgeValue; this.sourceNode = sourceNode; this.destNode = destNode; } @Override public DiGraphNode getSource() { return sourceNode; } @Override public DiGraphNode getDestination() { return destNode; } @Override public void setDestination(DiGraphNode node) { destNode = node; } @Override public void setSource(DiGraphNode node) { sourceNode = node; } @Override public E getValue() { return value; } @Override public A getAnnotation() { throw new UnsupportedOperationException( "Graph initialized with edge annotations turned off"); } @Override public void setAnnotation(Annotation data) { throw new UnsupportedOperationException( "Graph initialized with edge annotations turned off"); } @Override public String getColor() { return "black"; } @Override public String getLabel() { return String.valueOf(value); } @Override public String getNode1Id() { return ((LinkedDirectedGraphNode) sourceNode).getId(); } @Override public String getNode2Id() { return ((LinkedDirectedGraphNode) destNode).getId(); } @Override public String toString() { return sourceNode + " -> " + destNode; } @Override public GraphNode getNodeA() { return sourceNode; } @Override public GraphNode getNodeB() { return destNode; } } /** * A directed graph edge that stores the source and destination nodes at each * edge. */ static class AnnotatedLinkedDirectedGraphEdge extends LinkedDirectedGraphEdge { protected Annotation annotation; /** * Constructor. * * @param edgeValue Edge Value. */ AnnotatedLinkedDirectedGraphEdge(DiGraphNode sourceNode, E edgeValue, DiGraphNode destNode) { super(sourceNode, edgeValue, destNode); } @SuppressWarnings("unchecked") @Override public A getAnnotation() { return (A) annotation; } @Override public void setAnnotation(Annotation data) { annotation = data; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy