/*******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package com.ibm.wala.util.graph.traverse;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.collections.ReverseIterator;
import com.ibm.wala.util.graph.Graph;
import com.ibm.wala.util.graph.impl.GraphInverter;
/**
* This class computes strongly connected components for a Graph (or a subset of
* it). It does not store the SCCs in any lookaside structure, but rather simply
* generates an enumeration of them. See Cormen, Leiserson, Rivest Ch. 23 Sec. 5
*/
public class SCCIterator<T> implements Iterator<Set<T>> {
/**
* The second DFS (the reverse one) needed while computing SCCs
*/
final private DFSFinishTimeIterator<T> rev;
/**
* Construct an enumeration across the SCCs of a given graph.
*
* @param G
* The graph over which to construct SCCs
* @throws NullPointerException if G is null
*/
public SCCIterator(Graph<T> G) throws NullPointerException {
this(G, G == null ? null : G.iterator());
}
/**
* Construct an enumeration of the SCCs of the subset of a given graph
* determined by starting at a given set of nodes.
*/
public SCCIterator(Graph<T> G, Iterator<T> nodes) {
if (G == null) {
throw new IllegalArgumentException("G cannot be null");
}
Iterator<T> reverseFinishTime = ReverseIterator.reverse(DFS.iterateFinishTime(G, nodes));
rev = DFS.iterateFinishTime(GraphInverter.invert(G), reverseFinishTime);
}
/**
* Determine whether there are any more SCCs remaining in this enumeration.
*/
@Override
public boolean hasNext() {
return rev.hasNext();
}
/**
* Find the next SCC in this enumeration
*/
@Override
public Set<T> next() throws NoSuchElementException {
Set<T> currentSCC = HashSetFactory.make();
T v = rev.next();
currentSCC.add(v);
while (rev.hasNext() && !rev.isEmpty()) {
currentSCC.add(rev.next());
}
return currentSCC;
}
@Override
public void remove() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
}