Package dk.brics.xact.analysis.xmlgraph

Source Code of dk.brics.xact.analysis.xmlgraph.ForwardsXGAnalyzer

package dk.brics.xact.analysis.xmlgraph;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Set;

import dk.brics.string.util.MultiMap;
import dk.brics.xmlgraph.MultiContentNode;
import dk.brics.xmlgraph.NoContentNode;
import dk.brics.xmlgraph.Node;
import dk.brics.xmlgraph.NodeProcessor;
import dk.brics.xmlgraph.SingleContentNode;
import dk.brics.xmlgraph.XMLGraph;

/**
* Base class for performing forwards dataflow analysis on XML graphs.
* Subclasses should call {@link #doAnalysis()} when the analysis should be
* performed, which by convention should be at the end of its constructor.
* <p/>
* Only reachable nodes are analyzed &ndash; requesting the lattice point for an
* unreachable node will always return <tt>null</tt>.
*
* @param <T> lattice type. Requires a working {@link #equals(Object)}.
*/
public abstract class ForwardsXGAnalyzer<T> {
   
    private XMLGraph xg;
    private MultiMap<Integer,Integer> backedges = new MultiMap<Integer,Integer>();
    private Map<Integer, T> map = new HashMap<Integer, T>();
    private HashSet<Integer> inqueue = new HashSet<Integer>();
    private PriorityQueue<Integer> queue = new PriorityQueue<Integer>();
    private Map<Integer, Integer> node2priority = new HashMap<Integer,Integer>();
    private ArrayList<Integer> priority2node = new ArrayList<Integer>();
   
    public ForwardsXGAnalyzer(XMLGraph xg) {
        this.xg = xg;
    }
   
    protected void doAnalysis() {
        xg.processReachableNodes(new NodeProcessor<Object>() {
            @Override
            public Object process(MultiContentNode n) {
                initialize(n);
                for (int child : n.getContents()) {
                    backedges.add(child, n.getIndex());
                }
                return this;
            }
            @Override
            public Object process(SingleContentNode n) {
                initialize(n);
                backedges.add(n.getContent(), n.getIndex());
                return this;
            }
            @Override
            public Object process(NoContentNode n) {
                initialize(n);
                return this;
            }
            private void initialize(Node node) {
                map.put(node.getIndex(), bottom());
            }
        });
        for (int x : initialNodes()) {
            map.put(x, initial(xg.getNode(x)));
            enqueue(x);
        }
        while (!queue.isEmpty()) {
            int p = queue.remove();
            inqueue.remove(p);
            int index = priority2node.get(p);
            Node node = xg.getNode(index);
            T src = map.get(index);
            transfer(src, node);
        }
    }
   
    public XMLGraph getXmlGraph() {
        return xg;
    }
   
    private void enqueue(int index) {
        Integer p = node2priority.get(index);
        if (p == null) {
            p = node2priority.size();
            node2priority.put(index, p);
            priority2node.add(index);
        }
        if (inqueue.add(p)) {
            queue.add(p);
        }
    }
   
    /**
     * Returns the lattice data associated with the given node;
     * or <tt>null</tt> if the node is unreachable.
     * @param index index of a node
     * @return a lattice point
     */
    public T get(int index) {
        return map.get(index);
    }

    /**
     * Returns the lattice data associated with the given node;
     * or <tt>null</tt> if the node is unreachable.
     * @param node a node
     * @return a lattice point
     */
    public T get(Node node) {
        return map.get(node.getIndex());
    }
   
    /**
     * Changes the lattice point for the specified node. The underlying
     * worklist is updated if the new value is different from the old value.
     * <p/>
     * Note that this method does not perform any least upper bound
     * computation &ndash; you often want to merge with the existing value
     * before calling {@code put}.
     * @param index
     * @param newValue
     */
    protected void put(int index, T newValue) {
        T old = map.get(index);
        if (!old.equals(newValue)) {
            map.put(index, newValue);
            enqueue(index);
        }
    }
   
    /**
     * Transfer data from the specified node to its children.
     * Update node data using {@link #put(int, Object)}.
     * @param src lattice point for the specified node, provided for convenience
     * @param node the node to transfer from
     */
    protected abstract void transfer(T src, Node node);
   
    /**
     * Returns BOTTOM element.
     * @return a lattice point
     */
    protected abstract T bottom();
   
    /**
     * Returns initial value for the specified node.
     * @param node one of the nodes whose index was returned by {@link #initialNodes()}
     * @return a lattice point
     */
    protected abstract T initial(Node node);
   
    /**
     * Returns the initial nodes. This will typically be the root nodes in the XML graph.
     * All initial nodes must be reachable from the graph's root nodes.
     * @return read-only set
     */
    protected abstract Set<Integer> initialNodes();
   
}
TOP

Related Classes of dk.brics.xact.analysis.xmlgraph.ForwardsXGAnalyzer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.