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 com.google.common.annotations.Beta;
11 import com.google.common.base.Preconditions;
12 import java.util.ArrayList;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Objects;
19 * Utility class that provides topological sort.
22 * Note this class is non-public to allow for API transition.
25 public final class TopologicalSort {
28 * It isn't desirable to create instance of this class.
30 private TopologicalSort() {
34 * Topological sort of dependent nodes in acyclic graphs.
36 * @param nodes graph nodes
37 * @return Sorted {@link List} of {@link Node}s. Order: Nodes with no dependencies starting.
38 * @throws IllegalStateException when cycle is present in the graph
40 public static List<Node> sort(final Set<Node> nodes) {
41 List<Node> sortedNodes = new ArrayList<>(nodes.size());
43 Set<Node> dependentNodes = getDependentNodes(nodes);
45 while (!dependentNodes.isEmpty()) {
46 Node node = dependentNodes.iterator().next();
47 dependentNodes.remove(node);
49 sortedNodes.add(node);
51 for (Edge edge : node.getInEdges()) {
52 Node referent = edge.getFrom();
53 referent.getOutEdges().remove(edge);
55 if (referent.getOutEdges().isEmpty()) {
56 dependentNodes.add(referent);
66 private static Set<Node> getDependentNodes(final Set<Node> nodes) {
67 Set<Node> dependentNodes = new HashSet<>();
68 for (Node node : nodes) {
69 if (node.getOutEdges().isEmpty()) {
70 dependentNodes.add(node);
73 return dependentNodes;
76 private static void detectCycles(final Set<Node> nodes) {
78 boolean cycle = false;
79 Node cycledNode = null;
81 for (Node node : nodes) {
82 if (!node.getOutEdges().isEmpty()) {
88 Preconditions.checkState(!cycle, "Cycle detected in graph around node: " + cycledNode);
92 * Interface for nodes in graph that can be sorted topologically.
95 public interface Node {
96 Set<Edge> getInEdges();
98 Set<Edge> getOutEdges();
102 * Interface for edges in graph that can be sorted topologically.
105 public interface Edge {
112 * Basic Node implementation.
115 public static class NodeImpl implements Node {
116 private final Set<Edge> inEdges;
117 private final Set<Edge> outEdges;
120 inEdges = new HashSet<>();
121 outEdges = new HashSet<>();
125 public Set<Edge> getInEdges() {
130 public Set<Edge> getOutEdges() {
134 public void addEdge(final Node to) {
135 Edge edge = new EdgeImpl(this, to);
137 to.getInEdges().add(edge);
142 * Basic Edge implementation.
145 public static class EdgeImpl implements Edge {
146 private final Node from;
147 private final Node to;
149 public EdgeImpl(final Node from, final Node to) {
155 public Node getFrom() {
160 public Node getTo() {
165 public int hashCode() {
166 final int prime = 31;
168 result = prime * result + Objects.hashCode(from);
169 result = prime * result + Objects.hashCode(to);
174 public boolean equals(final Object obj) {
181 if (getClass() != obj.getClass()) {
184 EdgeImpl other = (EdgeImpl) obj;
186 if (other.from != null) {
189 } else if (!from.equals(other.from)) {
193 if (other.to != null) {
196 } else if (!to.equals(other.to)) {