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

com.google.javascript.jscomp.graph.LinkedUndirectedGraph 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.

There is a newer version: v20240317
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 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.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.jspecify.nullness.Nullable;

/**
 * An undirected graph using linked list within nodes to store edge
 * information.
 *
 *
 * @param  Value type that the graph node stores.
 * @param  Value type that the graph edge stores.
 */
public final class LinkedUndirectedGraph
    extends UndiGraph implements GraphvizGraph {
  final Map> nodes = new LinkedHashMap<>();

  @Override
  public SubGraph newSubGraph() {
    return new SimpleSubGraph<>(this);
  }

  public static  LinkedUndirectedGraph create() {
    return new LinkedUndirectedGraph<>(true, true);
  }

  private final boolean useNodeAnnotations;
  private final boolean useEdgeAnnotations;

  LinkedUndirectedGraph(boolean useNodeAnnotations, boolean useEdgeAnnotations) {
    this.useNodeAnnotations = useNodeAnnotations;
    this.useEdgeAnnotations = useEdgeAnnotations;
  }

  @Override
  public void connect(N srcValue, E edgeValue, N destValue) {
    LinkedUndirectedGraphNode src = getNodeOrFail(srcValue);
    LinkedUndirectedGraphNode dest = getNodeOrFail(destValue);
    LinkedUndirectedGraphEdge edge =
        useEdgeAnnotations ?
        new AnnotatedLinkedUndirectedGraphEdge<>(src, edgeValue, dest) :
        new LinkedUndirectedGraphEdge<>(src, edgeValue, dest);
    src.getNeighborEdges().add(edge);
    dest.getNeighborEdges().add(edge);
  }

  @Override
  public void disconnect(N srcValue, N destValue) {
    LinkedUndirectedGraphNode src = getNodeOrFail(srcValue);
    LinkedUndirectedGraphNode dest = getNodeOrFail(destValue);
    for (UndiGraphEdge edge :
      getUndirectedGraphEdges(srcValue, destValue)) {
      src.getNeighborEdges().remove(edge);
      dest.getNeighborEdges().remove(edge);
    }
  }

  @Override
  public UndiGraphNode createUndirectedGraphNode(
      N nodeValue) {
    return nodes.computeIfAbsent(
        nodeValue,
        (N k) ->
            useNodeAnnotations
                ? new AnnotatedLinkedUndirectedGraphNode(k)
                : new LinkedUndirectedGraphNode(k));
  }

  @Override
  public List> getNeighborNodes(N value) {
    UndiGraphNode uNode = getUndirectedGraphNode(value);
    return ((LinkedUndirectedGraphNode) uNode).neighborList();
  }

  @SuppressWarnings("unchecked")
  @Override
  public @Nullable List> getUndirectedGraphEdges(N n1, N n2) {
    UndiGraphNode dNode1 = nodes.get(n1);
    if (dNode1 == null) {
      return null;
    }
    UndiGraphNode dNode2 = nodes.get(n2);
    if (dNode2 == null) {
      return null;
    }
    List> edges = new ArrayList<>();
    for (UndiGraphEdge outEdge : dNode1.getNeighborEdges()) {
      if (outEdge.getNodeA() == dNode2 || outEdge.getNodeB() == dNode2) {
        edges.add(outEdge);
      }
    }
    return edges;
  }

  @Override
  public UndiGraphNode getUndirectedGraphNode(N nodeValue) {
    return nodes.get(nodeValue);
  }

  @Override
  public Collection> getUndirectedGraphNodes() {
    return Collections.unmodifiableCollection(nodes.values());
  }

  @Override
  public GraphNode createNode(N value) {
    return createUndirectedGraphNode(value);
  }

  @Override
  public List> getEdges(N n1, N n2) {
    return Collections.unmodifiableList(getUndirectedGraphEdges(n1, n2));
  }

  @SuppressWarnings("unchecked")
  @Override
  public List> getEdges() {
    List> result = new ArrayList<>();
    for (LinkedUndirectedGraphNode node : nodes.values()) {
      for (UndiGraphEdge edge : node.getNeighborEdges()) {
        if (edge.getNodeA() == node) {
          result.add(edge);
        }
      }
    }
    return result;
  }

  @Override
  public @Nullable GraphEdge getFirstEdge(N n1, N n2) {
    UndiGraphNode dNode1 = getNodeOrFail(n1);
    UndiGraphNode dNode2 = getNodeOrFail(n2);
    for (UndiGraphEdge outEdge : dNode1.getNeighborEdges()) {
      if (outEdge.getNodeA() == dNode2 || outEdge.getNodeB() == dNode2) {
        return outEdge;
      }
    }
    return null;
  }

  @Override
  public GraphNode getNode(N value) {
    return getUndirectedGraphNode(value);
  }

  @Override
  public boolean isConnected(N n1, N n2) {
    return isConnected(n1, Predicates.alwaysTrue(), n2);
  }

  @Override
  public boolean isConnected(N n1, E e, N n2) {
    return isConnected(n1, Predicates.equalTo(e), n2);
  }

  private boolean isConnected(N n1, Predicate edgePredicate, N n2) {
    UndiGraphNode dNode1 = nodes.get(n1);
    if (dNode1 == null) {
      return false;
    }
    UndiGraphNode dNode2 = nodes.get(n2);
    if (dNode2 == null) {
      return false;
    }
    for (UndiGraphEdge outEdge : dNode1.getNeighborEdges()) {
      if ((outEdge.getNodeA() == dNode1 && outEdge.getNodeB() == dNode2) ||
          (outEdge.getNodeA() == dNode2 && outEdge.getNodeB() == dNode1)) {
        if (edgePredicate.apply(outEdge.getValue())) {
          return true;
        }
      }
    }
    return false;
  }

  @Override
  public List getGraphvizEdges() {
    List edgeList = new ArrayList<>();
    for (LinkedUndirectedGraphNode node : nodes.values()) {
      for (UndiGraphEdge edge : node.getNeighborEdges()) {
        if (edge.getNodeA() == node) {
          edgeList.add((GraphvizEdge) edge);
        }
      }
    }
    return edgeList;
  }

  @Override
  public String getName() {
    return "LinkedUndirectedGraph";
  }

  @Override
  public List getGraphvizNodes() {
    List nodeList = new ArrayList<>(nodes.size());
    for (LinkedUndirectedGraphNode node : nodes.values()) {
      nodeList.add(node);
    }
    return nodeList;
  }

  @Override
  public boolean isDirected() {
    return false;
  }

  @Override
  public Collection> getNodes() {
    return Collections.unmodifiableCollection(nodes.values());
  }

  @Override
  public int getNodeCount() {
    return nodes.size();
  }

  @Override
  public int getNodeDegree(N value) {
    UndiGraphNode uNode = getUndirectedGraphNode(value);
    if (uNode == null) {
      throw new IllegalArgumentException(value + " not found in graph");
    }
    return uNode.getNeighborEdges().size();
  }

  /**
   * An undirected graph node that stores outgoing edges and incoming edges as
   * an list within the node itself.
   */
  static class LinkedUndirectedGraphNode implements UndiGraphNode,
      GraphvizNode {

    private final List> neighborEdges = new ArrayList<>();
    private final N value;

    LinkedUndirectedGraphNode(N nodeValue) {
      this.value = nodeValue;
    }

    @Override
    public List> getNeighborEdges() {
      return neighborEdges;
    }

    @Override
    public Iterator> getNeighborEdgesIterator() {
      return neighborEdges.iterator();
    }

    @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 N getValue() {
      return value;
    }

    @Override
    public String getColor() {
      return "white";
    }

    @Override
    public String getId() {
      return "LDN" + hashCode();
    }

    @Override
    public String getLabel() {
      return String.valueOf(value);
    }

    private List> neighborList() {
      List> result = new ArrayList<>(neighborEdges.size());
      for (UndiGraphEdge edge : neighborEdges) {
        if (edge.getNodeA() == this) {
          result.add(edge.getNodeB());
        } else {
          result.add(edge.getNodeA());
        }
      }
      return result;
    }
  }

  /**
   * An undirected graph node with annotations.
   */
  static class AnnotatedLinkedUndirectedGraphNode
      extends LinkedUndirectedGraphNode {

    protected Annotation annotation;

    AnnotatedLinkedUndirectedGraphNode(N nodeValue) {
      super(nodeValue);
    }

    @SuppressWarnings("unchecked")
    @Override
    public  A getAnnotation() {
      return (A) annotation;
    }

    @Override
    public void setAnnotation(Annotation data) {
      annotation = data;
    }
  }

  /**
   * An undirected graph edge that stores two nodes at each edge.
   */
  static class LinkedUndirectedGraphEdge implements UndiGraphEdge,
      GraphvizEdge {

    private final UndiGraphNode nodeA;
    private final UndiGraphNode nodeB;
    protected final E value;

    LinkedUndirectedGraphEdge(UndiGraphNode nodeA, E edgeValue,
        UndiGraphNode nodeB) {
      this.value = edgeValue;
      this.nodeA = nodeA;
      this.nodeB = nodeB;
    }

    @Override
    public E getValue() {
      return value;
    }

    @Override
    public GraphNode getNodeA() {
      return nodeA;
    }

    @Override
    public GraphNode getNodeB() {
      return nodeB;
    }

    @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);
    }

    @SuppressWarnings("unchecked")
    @Override
    public String getNode1Id() {
      return ((LinkedUndirectedGraphNode) nodeA).getId();
    }

    @SuppressWarnings("unchecked")
    @Override
    public String getNode2Id() {
      return ((LinkedUndirectedGraphNode) nodeB).getId();
    }

    @Override
    public String toString() {
      return nodeA + " -- " + nodeB;
    }
  }

  /**
   * An annotated undirected graph edge..
   */
  static class AnnotatedLinkedUndirectedGraphEdge
      extends LinkedUndirectedGraphEdge {

    protected Annotation annotation;

    AnnotatedLinkedUndirectedGraphEdge(
        UndiGraphNode nodeA, E edgeValue,
        UndiGraphNode nodeB) {
      super(nodeA, edgeValue, nodeB);
    }

    @SuppressWarnings("unchecked")
    @Override
    public  A getAnnotation() {
      return (A) annotation;
    }

    @Override
    public void setAnnotation(Annotation data) {
      annotation = data;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy