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

org.antlr.v4.misc.Graph Maven / Gradle / Ivy

There is a newer version: 4.9.0
Show newest version
/*
 * Copyright (c) 2012 The ANTLR Project. All rights reserved.
 * Use of this file is governed by the BSD-3-Clause license that
 * can be found in the LICENSE.txt file in the project root.
 */
package org.antlr.v4.misc;

import org.antlr.v4.runtime.misc.OrderedHashSet;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/** A generic graph with edges; Each node as a single Object payload.
 *  This is only used to topologically sort a list of file dependencies
 *  at the moment.
 */
public class Graph {

	public static class Node {
		public T payload;
		public List> edges = Collections.emptyList(); // points at which nodes?

		public Node(T payload) { this.payload = payload; }

		public void addEdge(Node n) {
			if ( edges==Collections.EMPTY_LIST ) edges = new ArrayList>();
			if ( !edges.contains(n) ) edges.add(n);
		}

		@Override
		public String toString() { return payload.toString(); }
	}

	/** Map from node payload to node containing it */
	protected Map> nodes = new LinkedHashMap>();

	public void addEdge(T a, T b) {
		//System.out.println("add edge "+a+" to "+b);
		Node a_node = getNode(a);
		Node b_node = getNode(b);
		a_node.addEdge(b_node);
	}

	public Node getNode(T a) {
		Node existing = nodes.get(a);
		if ( existing!=null ) return existing;
		Node n = new Node(a);
		nodes.put(a, n);
		return n;
	}

	/** DFS-based topological sort.  A valid sort is the reverse of
	 *  the post-order DFA traversal.  Amazingly simple but true.
	 *  For sorting, I'm not following convention here since ANTLR
	 *  needs the opposite.  Here's what I assume for sorting:
	 *
	 *    If there exists an edge u -> v then u depends on v and v
	 *    must happen before u.
	 *
	 *  So if this gives nonreversed postorder traversal, I get the order
	 *  I want.
	 */
	public List sort() {
		Set> visited = new OrderedHashSet>();
		ArrayList sorted = new ArrayList();
		while ( visited.size() < nodes.size() ) {
			// pick any unvisited node, n
			Node n = null;
			for (Node tNode : nodes.values()) {
				n = tNode;
				if ( !visited.contains(n) ) break;
			}
			if (n!=null) { // if at least one unvisited
				DFS(n, visited, sorted);
			}
		}
		return sorted;
	}

	public void DFS(Node n, Set> visited, ArrayList sorted) {
		if ( visited.contains(n) ) return;
		visited.add(n);
		if ( n.edges!=null ) {
			for (Node target : n.edges) {
				DFS(target, visited, sorted);
			}
		}
		sorted.add(n.payload);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy