2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.util;
10 import static com.google.common.base.Preconditions.checkState;
12 import com.google.common.annotations.Beta;
13 import java.util.ArrayList;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Objects;
20 * Utility class that provides topological sort.
23 * Note this class is non-public to allow for API transition.
26 public final class TopologicalSort {
29 * It isn't desirable to create instance of this class.
31 private TopologicalSort() {
35 * Topological sort of dependent nodes in acyclic graphs.
37 * @param nodes graph nodes
38 * @return Sorted {@link List} of {@link Node}s. Order: Nodes with no dependencies starting.
39 * @throws IllegalStateException when cycle is present in the graph
41 public static List<Node> sort(final Set<Node> nodes) {
42 List<Node> sortedNodes = new ArrayList<>(nodes.size());
44 Set<Node> dependentNodes = getDependentNodes(nodes);
46 while (!dependentNodes.isEmpty()) {
47 Node node = dependentNodes.iterator().next();
48 dependentNodes.remove(node);
50 sortedNodes.add(node);
52 for (Edge edge : node.getInEdges()) {
53 Node referent = edge.getFrom();
54 referent.getOutEdges().remove(edge);
56 if (referent.getOutEdges().isEmpty()) {
57 dependentNodes.add(referent);
67 private static Set<Node> getDependentNodes(final Set<Node> nodes) {
68 Set<Node> dependentNodes = new HashSet<>();
69 for (Node node : nodes) {
70 if (node.getOutEdges().isEmpty()) {
71 dependentNodes.add(node);
74 return dependentNodes;
77 private static void detectCycles(final Set<Node> nodes) {
79 boolean cycle = false;
80 Node cycledNode = null;
82 for (Node node : nodes) {
83 if (!node.getOutEdges().isEmpty()) {
89 checkState(!cycle, "Cycle detected in graph around node: " + cycledNode);
93 * Interface for nodes in graph that can be sorted topologically.
96 public interface Node {
97 Set<Edge> getInEdges();
99 Set<Edge> getOutEdges();
103 * Interface for edges in graph that can be sorted topologically.
106 public interface Edge {
113 * Basic Node implementation.
116 public static class NodeImpl implements Node {
117 private final Set<Edge> inEdges = new HashSet<>();
118 private final Set<Edge> outEdges = new HashSet<>();
121 public Set<Edge> getInEdges() {
126 public Set<Edge> getOutEdges() {
130 public void addEdge(final Node to) {
131 Edge edge = new EdgeImpl(this, to);
133 to.getInEdges().add(edge);
138 * Basic Edge implementation.
141 public static class EdgeImpl implements Edge {
142 private final Node from;
143 private final Node to;
145 public EdgeImpl(final Node from, final Node to) {
151 public Node getFrom() {
156 public Node getTo() {
161 public int hashCode() {
162 final int prime = 31;
164 result = prime * result + Objects.hashCode(from);
165 result = prime * result + Objects.hashCode(to);
170 public boolean equals(final Object obj) {
177 if (getClass() != obj.getClass()) {
180 EdgeImpl other = (EdgeImpl) obj;
182 if (other.from != null) {
185 } else if (!from.equals(other.from)) {
189 if (other.to != null) {
192 } else if (!to.equals(other.to)) {