/* * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.flex.abc.graph.algorithms; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Set; import java.util.Stack; import org.apache.flex.abc.graph.IBasicBlock; import org.apache.flex.abc.graph.IFlowgraph; /** * DepthFirstPreorderIterator yields a depth-first preorder traversal of a {@link IFlowgraph}. */ public class DepthFirstPreorderIterator implements Iterator<IBasicBlock> { /** * @param roots the caller's root(s) of the flowgraph. * There should be only one start block, but multiple roots * are tolerated to work around fuzzy successor logic to * exception handlers. */ public DepthFirstPreorderIterator(Collection<? extends IBasicBlock> roots) { this.toDo.addAll(roots); } /** * The to-be-visited stack of blocks. */ Stack<IBasicBlock> toDo = new Stack<IBasicBlock>(); /** * The set of edges already traversed. */ Set<Edge> visitedEdges = new HashSet<Edge>(); @Override public boolean hasNext() { return !toDo.isEmpty(); } @Override public IBasicBlock next() { if (!hasNext()) throw new NoSuchElementException(); IBasicBlock next = toDo.pop(); pushSuccessors(next); return next; } /** * Traverse any previously-untraversed edges * by adding the destination block to the to-do stack. * @param b the current block. */ private void pushSuccessors(IBasicBlock b) { for (IBasicBlock succ_block : b.getSuccessors()) if (visitedEdges.add(new Edge(b, succ_block))) toDo.push(succ_block); } @Override public void remove() { throw new UnsupportedOperationException(); } /** * Edge is used to detect edges previously traversed. * It implements composite hash and equality operations * so it can be used as a key in a hashed collection. */ private static class Edge { private IBasicBlock from; private IBasicBlock to; Edge(IBasicBlock from, IBasicBlock to) { this.from = from; this.to = to; } private static final int PRIME_MULTIPLIER = 7057; /** * Generate a composite hash code so that an Edge can be * used in a hashed container. * @return the composite hash code of the from/to vertices. */ @Override public int hashCode() { return (from.hashCode() * PRIME_MULTIPLIER) + to.hashCode(); } /** * Use the vertices to determine equality of an Edge so it * can be used in a hashed container. * @param other the other object to compare. * @return true iff other is an Edge, and both Edges' from/to * vertices match their corresponding field. */ @Override public boolean equals(Object other) { if (other == this) { return true; } else if (other instanceof Edge) { Edge otherEdge = (Edge)other; return from == otherEdge.from && to == otherEdge.to; } return false; } } }