1 cananian   1.1      // CycleEq.java, created Wed Oct 14 08:15:53 1998 by cananian
  2 cananian   1.4      // Copyright (C) 1998 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian   1.4      // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian   1.1      package harpoon.Analysis;
  5 cananian   1.1      
  6 cananian   1.4.2.6  import harpoon.ClassFile.HCode;
  7 cananian   1.4.2.6  import harpoon.ClassFile.HCodeEdge;
  8 cananian   1.4.2.6  import harpoon.ClassFile.HCodeElement;
  9 cananian   1.4.2.21 import harpoon.IR.Properties.CFGraphable;
 10 cananian   1.9      import net.cscott.jutil.UnmodifiableIterator;
 11 cananian   1.1      import harpoon.Util.Util;
 12 cananian   1.1      
 13 cananian   1.4.2.8  import java.util.ArrayList;
 14 cananian   1.4.2.8  import java.util.Collection;
 15 cananian   1.4.2.8  import java.util.Collections;
 16 cananian   1.4.2.8  import java.util.HashMap;
 17 cananian   1.4.2.8  import java.util.HashSet;
 18 cananian   1.4.2.8  import java.util.Iterator;
 19 cananian   1.4.2.10 import java.util.LinkedList;
 20 cananian   1.4.2.8  import java.util.List;
 21 cananian   1.4.2.8  import java.util.Map;
 22 sportbilly 1.4.2.18 import java.util.NoSuchElementException;
 23 cananian   1.4.2.8  import java.util.Set;
 24 cananian   1.1      import java.util.Stack;
 25 cananian   1.4.2.8  
 26 cananian   1.1      /**
 27 sportbilly 1.4.2.18  * <code>CycleEq</code> computes cycle equivalence classes for edges in
 28 cananian   1.3       * a control flow graph, in O(E) time.
 29 cananian   1.1       * 
 30 cananian   1.4       * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 31 cananian   1.9       * @version $Id: CycleEq.java,v 1.9 2004/02/08 01:49:03 cananian Exp $
 32 cananian   1.1       */
 33 cananian   1.1      
 34 cananian   1.1      public class CycleEq  {
 35 sportbilly 1.4.2.18     /* List of <code>HCodeEdge</code>s in DFS order */
 36 sportbilly 1.4.2.18     private List elements = new ArrayList();
 37 sportbilly 1.4.2.18     /* Mapping of cycle equivalency class object to <code>List</code>
 38 sportbilly 1.4.2.18      * of <code>HCodeEdge</code>s in that equivalency class. */
 39 sportbilly 1.4.2.18     private Map equiv = new HashMap();
 40 sportbilly 1.4.2.18 
 41 cananian   1.1          public CycleEq(HCode hc) {
 42 sportbilly 1.4.2.18         Graph g = new Graph(hc); // compute cycle equivalency
 43 sportbilly 1.4.2.18         // DFS search to order elements in cycle-equivalency classes.
 44 sportbilly 1.4.2.18         dfs(g, hc.getRootElement(), new HashSet());
 45 cananian   1.4.2.9          // make equiv and elements unmodifiable.
 46 cananian   1.4.2.8          equiv = Collections.unmodifiableMap(equiv);
 47 cananian   1.4.2.9          elements = Collections.unmodifiableList(elements);
 48 cananian   1.1              // throw away all temp info now.
 49 cananian   1.1          }
 50 sportbilly 1.4.2.18     private void dfs(Graph g, HCodeElement hce, Set mark) {
 51 cananian   1.4.2.19         Stack s = new Stack();
 52 cananian   1.4.2.19     newnode: // this is an obvious hack to allow a 'goto' statement
 53 cananian   1.4.2.19         do { // despite java's "prohibition".
 54 cananian   1.4.2.19             mark.add(hce);
 55 cananian   1.4.2.21             s.push(((CFGraphable)hce).succC().iterator());
 56 cananian   1.4.2.19             
 57 cananian   1.4.2.19             while (!s.isEmpty()) {
 58 cananian   1.4.2.19                 for (Iterator i = (Iterator) s.pop(); i.hasNext(); ) {
 59 cananian   1.4.2.19                     HCodeEdge e = (HCodeEdge)i.next();
 60 cananian   1.4.2.19                     Object cq = g.edge(e).CQclass;
 61 cananian   1.4.2.19                     List l = (List) equiv.get(cq);
 62 cananian   1.4.2.19                     if (l==null) { l = new LinkedList(); equiv.put(cq, l); }
 63 cananian   1.4.2.19                     l.add(e); // append edge to end of list.
 64 cananian   1.4.2.19                     elements.add(e);
 65 cananian   1.4.2.19                     // recurse
 66 cananian   1.4.2.19                     if (!mark.contains(e.to())) {
 67 cananian   1.4.2.19                         s.push(i);
 68 cananian   1.4.2.19                         hce = e.to();
 69 cananian   1.4.2.19                         continue newnode; // recurse to top of procedure.
 70 cananian   1.4.2.19                     }
 71 cananian   1.1                      }
 72 cananian   1.1                  }
 73 cananian   1.4.2.24             break;
 74 cananian   1.4.2.24         } while(true); // not really a loop.  Just a block.
 75 sportbilly 1.4.2.18     }
 76 cananian   1.4.2.9      /** Return <code>Collection</code> of cycle-equivalency
 77 cananian   1.4.2.9       *  <code>List</code>s. */
 78 cananian   1.4.2.8      public Collection cdClasses() { return equiv.values(); }
 79 sportbilly 1.4.2.18     /** Return <code>List</code> of edges in DFS order. */
 80 cananian   1.4.2.9      public List elements() { return elements; }
 81 cananian   1.1      
 82 sportbilly 1.4.2.18     /* ----------------------------------------------------- */
 83 cananian   1.1          
 84 sportbilly 1.4.2.18     /** Graph stored edge/node information for cycle-equivalency computation.
 85 sportbilly 1.4.2.18      *  Also adds synthetic END->START edge to make CFG an SCC. */
 86 sportbilly 1.4.2.18     static private class Graph {
 87 sportbilly 1.4.2.18         Map hce2node = new HashMap(); // map HCodeElements to nodes.
 88 sportbilly 1.4.2.18         Map hce2edge = new HashMap(); // map HCodeEdges to edges
 89 sportbilly 1.4.2.18         Map start_edges = new HashMap(); // from synthetic START to root.
 90 sportbilly 1.4.2.18         Map end_edges   = new HashMap(); // from synthetic END to leaves.
 91 sportbilly 1.4.2.18         Node START = new StartNode(); // synthetic START
 92 sportbilly 1.4.2.18         Node END = new EndNode();     // synthetic END
 93 sportbilly 1.4.2.18         List all_nodes = new ArrayList(); // all nodes, in dfs preorder.
 94 sportbilly 1.4.2.18         Graph(HCode c) {
 95 sportbilly 1.4.2.18             /* initialize graph */
 96 sportbilly 1.4.2.18             HCodeElement root = c.getRootElement();
 97 sportbilly 1.4.2.18             start_edges.put(root, new FakeEdge(START, node(root)));
 98 sportbilly 1.4.2.18             HCodeElement[] leaves = c.getLeafElements();
 99 sportbilly 1.4.2.18             for (int i=0; i<leaves.length; i++)
100 sportbilly 1.4.2.18                 end_edges.put(leaves[i], new FakeEdge(node(leaves[i]), END));
101 sportbilly 1.4.2.18             Edge e = new FakeEdge(START, END); // synthetic END->START edge
102 sportbilly 1.4.2.18             start_edges.put(null, e);
103 sportbilly 1.4.2.18             end_edges.put(null, e);
104 sportbilly 1.4.2.18             /* construct depth first spanning tree */
105 sportbilly 1.4.2.18             dfs(START, new HashSet());
106 sportbilly 1.4.2.18             /* compute cycle equivalence */
107 sportbilly 1.4.2.18             for (int i=all_nodes.size()-1; i>=0; i--) // dfs postorder
108 sportbilly 1.4.2.18                 cycle((Node)all_nodes.get(i));
109 sportbilly 1.4.2.18         }
110 sportbilly 1.4.2.18         /** Map HCodeElement to Node, creating new RealNode if necessary. */
111 sportbilly 1.4.2.18         Node node(HCodeElement hce) {
112 cananian   1.6.2.1              assert hce!=null;
113 sportbilly 1.4.2.18             Node n = (Node) hce2node.get(hce);
114 sportbilly 1.4.2.18             return (n!=null)?n:new RealNode(hce);
115 sportbilly 1.4.2.18         }
116 sportbilly 1.4.2.18         /** Map HCodeEdge to Edge, creating new RealEdge if necessary. */
117 sportbilly 1.4.2.18         Edge edge(HCodeEdge hce) {
118 cananian   1.6.2.1              assert hce!=null;
119 sportbilly 1.4.2.18             Edge e = (Edge) hce2edge.get(hce);
120 sportbilly 1.4.2.18             return (e!=null)?e:new RealEdge(hce);
121 sportbilly 1.4.2.18         }
122 sportbilly 1.4.2.18         /** Construct depth-first spanning tree. */
123 sportbilly 1.4.2.18         void dfs(Node n, Set mark) {
124 cananian   1.6.2.1              assert !mark.contains(n);
125 sportbilly 1.4.2.18             n.dfsnum = mark.size();
126 sportbilly 1.4.2.18             mark.add(n);
127 sportbilly 1.4.2.18             all_nodes.add(n);
128 sportbilly 1.4.2.18             for (Iterator i=n.adj(); i.hasNext(); ) {
129 sportbilly 1.4.2.18                 Edge e = (Edge) i.next();
130 sportbilly 1.4.2.18                 Node m = e.otherEnd(n); /* edge from n to m */
131 sportbilly 1.4.2.18                 if (!mark.contains(m)) { /* a tree edge (child) */
132 sportbilly 1.4.2.18                     n.children = new EdgeSList(e, n.children);
133 sportbilly 1.4.2.18                     m.parent = e;
134 sportbilly 1.4.2.18                     /* recurse */
135 sportbilly 1.4.2.18                     dfs(m, mark);
136 sportbilly 1.4.2.18                 } else if (!e.equals(n.parent)) { /* a backedge */
137 sportbilly 1.4.2.18                     n.backedges = new EdgeSList(e, n.backedges);
138 cananian   1.1                      }
139 cananian   1.1                  }
140 cananian   1.4.2.11         }
141 sportbilly 1.4.2.18         /** Compute cycle-equivalency */
142 sportbilly 1.4.2.18         void cycle(Node n) {
143 sportbilly 1.4.2.18             /** Compute hi(n) */
144 sportbilly 1.4.2.18             Node hi0 = null;
145 sportbilly 1.4.2.18             for (EdgeSList el=n.backedges; el!=null; el=el.next)
146 sportbilly 1.4.2.18                 if (hi0==null || el.e.otherEnd(n).dfsnum < hi0.dfsnum)
147 sportbilly 1.4.2.18                     hi0 = el.e.otherEnd(n);
148 sportbilly 1.4.2.18             Node hi1 = null, hi2 = null;
149 sportbilly 1.4.2.18             for (EdgeSList el=n.children; el!=null; el=el.next)
150 sportbilly 1.4.2.18                 if (hi1==null || el.e.otherEnd(n).hi.dfsnum < hi1.dfsnum) {
151 sportbilly 1.4.2.18                     if (hi2==null || hi1.dfsnum < hi2.dfsnum) hi2 = hi1;  
152 sportbilly 1.4.2.18                     hi1 = el.e.otherEnd(n).hi;
153 sportbilly 1.4.2.18                 } else if (hi2==null ||
154 sportbilly 1.4.2.18                            el.e.otherEnd(n).hi.dfsnum < hi2.dfsnum) {
155 sportbilly 1.4.2.18                     hi2 = el.e.otherEnd(n).hi; // second-highest.
156 cananian   1.4.2.3                  }
157 cananian   1.1      
158 sportbilly 1.4.2.18             n.hi = (hi0==null) ? hi1 : (hi1==null) ? hi0 :
159 sportbilly 1.4.2.18                 (hi0.dfsnum < hi1.dfsnum) ? hi0 : hi1;
160 cananian   1.1      
161 sportbilly 1.4.2.18             /* compute bracketlist */
162 cananian   1.1                  n.blist = new BracketList();
163 sportbilly 1.4.2.18             for (EdgeSList el=n.children; el!=null; el=el.next)
164 sportbilly 1.4.2.18                 n.blist.append(el.e.otherEnd(n).blist);
165 sportbilly 1.4.2.18             for (EdgeSList el=n.capping; el!=null; el=el.next)
166 sportbilly 1.4.2.18                 n.blist.delete(el.e);
167 sportbilly 1.4.2.18             for (EdgeSList el=n.backedges; el!=null; el=el.next)
168 sportbilly 1.4.2.18                 if (el.e.otherEnd(n).dfsnum > n.dfsnum) { /* descendant of n */
169 sportbilly 1.4.2.18                     n.blist.delete(el.e);
170 sportbilly 1.4.2.18                     if (el.e.CQclass==null)
171 sportbilly 1.4.2.18                         el.e.CQclass = new Object(); /* new CQ class */
172 cananian   1.1                      }
173 sportbilly 1.4.2.18             for (EdgeSList el=n.backedges; el!=null; el=el.next)
174 cananian   1.4.2.20                 if (el.e.otherEnd(n).dfsnum <= n.dfsnum) /*ancestor or itself*/
175 sportbilly 1.4.2.18                     n.blist.push(el.e);
176 sportbilly 1.4.2.18             if (hi2!=null &&
177 sportbilly 1.4.2.18                 (hi0==null || hi0.dfsnum > hi2.dfsnum)) {
178 sportbilly 1.4.2.18                 /* create capping backedge */
179 sportbilly 1.4.2.18                 Edge d = new FakeEdge(n, hi2);
180 sportbilly 1.4.2.18                 hi2.capping = new EdgeSList(d, hi2.capping);
181 sportbilly 1.4.2.18                 n.blist.push(d);
182 sportbilly 1.4.2.18             }
183 sportbilly 1.4.2.18 
184 sportbilly 1.4.2.18             /* determine class for edge from parent(n) to n */
185 sportbilly 1.4.2.18             Edge e = n.parent;
186 sportbilly 1.4.2.18             if (e!=null) {
187 sportbilly 1.4.2.18                 Edge b = n.blist.top();
188 sportbilly 1.4.2.18                 if (b.recentSize != n.blist.size()) {
189 sportbilly 1.4.2.18                     b.recentSize =  n.blist.size();
190 sportbilly 1.4.2.18                     b.recentClass=  new Object(); /* new CQ class */
191 cananian   1.1                      }
192 sportbilly 1.4.2.18                 e.CQclass = b.recentClass;
193 cananian   1.1      
194 sportbilly 1.4.2.18                 /* handle one tree one backedge case */
195 sportbilly 1.4.2.18                 if (b.recentSize==1)
196 sportbilly 1.4.2.18                     b.CQclass = e.CQclass;
197 sportbilly 1.4.2.18             }
198 sportbilly 1.4.2.18         }
199 sportbilly 1.4.2.18 
200 sportbilly 1.4.2.18         /** Graph node superclass */
201 sportbilly 1.4.2.18         abstract class Node {
202 sportbilly 1.4.2.18             int dfsnum = -1;
203 sportbilly 1.4.2.18             BracketList blist;
204 sportbilly 1.4.2.18             Node hi; // highest reachable from backedge originating below this
205 sportbilly 1.4.2.18             //
206 sportbilly 1.4.2.18             Edge      parent = null;
207 sportbilly 1.4.2.18             EdgeSList children = null;
208 sportbilly 1.4.2.18             EdgeSList backedges= null;
209 sportbilly 1.4.2.18             EdgeSList capping = null;
210 sportbilly 1.4.2.18 
211 sportbilly 1.4.2.18             abstract Iterator adj(); /* return all edges */
212 sportbilly 1.4.2.18             public abstract boolean equals(Object o);
213 sportbilly 1.4.2.18             public abstract int hashCode();
214 sportbilly 1.4.2.18             public String toString() { return "["+dfsnum+"]"; }
215 sportbilly 1.4.2.18         }
216 sportbilly 1.4.2.18         /** Synthetic START node */
217 sportbilly 1.4.2.18         class StartNode extends Node {
218 sportbilly 1.4.2.18             Iterator adj() { return start_edges.values().iterator(); }
219 sportbilly 1.4.2.18             public boolean equals(Object o) { return o instanceof StartNode; }
220 sportbilly 1.4.2.18             public int hashCode() { return 458543; }
221 sportbilly 1.4.2.18             public String toString() { return "START"; }
222 sportbilly 1.4.2.18         }
223 sportbilly 1.4.2.18         /** Synthetic END node */
224 sportbilly 1.4.2.18         class EndNode extends Node {
225 sportbilly 1.4.2.18             Iterator adj() { return end_edges.values().iterator(); }
226 sportbilly 1.4.2.18             public boolean equals(Object o) { return o instanceof EndNode; }
227 sportbilly 1.4.2.18             public int hashCode() { return 234913; }
228 sportbilly 1.4.2.18             public String toString() { return "END"; }
229 sportbilly 1.4.2.18         }
230 sportbilly 1.4.2.18         /** 'Real' node corresponding to an HCodeElement */
231 sportbilly 1.4.2.18         class RealNode extends Node {
232 sportbilly 1.4.2.18             final HCodeElement hce;
233 sportbilly 1.4.2.18             //
234 sportbilly 1.4.2.18             RealNode(HCodeElement hce) {
235 cananian   1.6.2.1                  assert hce!=null;
236 cananian   1.6.2.1                  assert !hce2node.containsKey(hce);
237 sportbilly 1.4.2.18                 this.hce = hce; hce2node.put(hce, this);
238 sportbilly 1.4.2.18             }
239 sportbilly 1.4.2.18             Iterator adj() {
240 sportbilly 1.4.2.18                 return new UnmodifiableIterator() {
241 cananian   1.4.2.21                     final HCodeEdge[] pred=((CFGraphable)hce).pred();
242 cananian   1.4.2.21                     final HCodeEdge[] succ=((CFGraphable)hce).succ();
243 sportbilly 1.4.2.18                     Edge se = (Edge) start_edges.get(hce);
244 sportbilly 1.4.2.18                     Edge ee = (Edge) end_edges.get(hce);
245 sportbilly 1.4.2.18                     int i=0, j=0;
246 sportbilly 1.4.2.18                     public boolean hasNext() {
247 sportbilly 1.4.2.18                         return (i<pred.length) || (j<succ.length) ||
248 sportbilly 1.4.2.18                             (se != null) || (ee != null);
249 cananian   1.4.2.2                      }
250 sportbilly 1.4.2.18                     public Object next() {
251 sportbilly 1.4.2.18                         if (i<pred.length)
252 sportbilly 1.4.2.18                             return edge(pred[i++]);
253 sportbilly 1.4.2.18                         if (j<succ.length)
254 sportbilly 1.4.2.18                             return edge(succ[j++]);
255 sportbilly 1.4.2.18                         if (se!=null) { Edge e=se; se=null; return e; }
256 sportbilly 1.4.2.18                         if (ee!=null) { Edge e=ee; ee=null; return e; }
257 sportbilly 1.4.2.18                         throw new NoSuchElementException();
258 cananian   1.4.2.2                      }
259 cananian   1.4.2.2                  };
260 cananian   1.4.2.4              }
261 sportbilly 1.4.2.18             public int hashCode() { return hce.hashCode(); }
262 sportbilly 1.4.2.18             public boolean equals(Object o) {
263 sportbilly 1.4.2.18                 RealNode rn;
264 sportbilly 1.4.2.18                 if (this==o) return true;
265 sportbilly 1.4.2.18                 if (null==o) return false;
266 sportbilly 1.4.2.18                 try { rn = (RealNode) o; }
267 sportbilly 1.4.2.18                 catch (ClassCastException e) { return false; }
268 sportbilly 1.4.2.18                 return rn.hce.equals(hce);
269 sportbilly 1.4.2.18             }
270 sportbilly 1.4.2.18             public String toString()
271 sportbilly 1.4.2.18                 { return super.toString()+" "+hce.toString(); }
272 sportbilly 1.4.2.18         }
273 sportbilly 1.4.2.18 
274 sportbilly 1.4.2.18         /** Graph edge superclass */
275 sportbilly 1.4.2.18         abstract class Edge {
276 sportbilly 1.4.2.18             Object CQclass = null;
277 sportbilly 1.4.2.18             int recentSize;
278 sportbilly 1.4.2.18             Object recentClass;
279 sportbilly 1.4.2.18             EdgeDList container;
280 sportbilly 1.4.2.18             //
281 sportbilly 1.4.2.18             public abstract Node otherEnd(Node n);
282 sportbilly 1.4.2.18             public int hashCode() { throw new Error("Unimplemented."); }
283 sportbilly 1.4.2.18             public abstract String toString();
284 sportbilly 1.4.2.18         }
285 sportbilly 1.4.2.18         /** 'Real' edge corresponding to HCodeEdge */
286 sportbilly 1.4.2.18         class RealEdge extends Edge {
287 sportbilly 1.4.2.18             final HCodeEdge hce;
288 sportbilly 1.4.2.18             RealEdge(HCodeEdge hce) {
289 cananian   1.6.2.1                  assert hce!=null;
290 cananian   1.6.2.1                  assert !hce2edge.containsKey(hce);
291 sportbilly 1.4.2.18                 this.hce = hce; hce2edge.put(hce, this);
292 sportbilly 1.4.2.18             }
293 sportbilly 1.4.2.18             public Node otherEnd(Node n) {
294 sportbilly 1.4.2.18                 RealNode rn = (RealNode) n; /* RealEdge connects RealNodes */
295 sportbilly 1.4.2.18                 return node(hce.from().equals(rn.hce)?hce.to():hce.from());
296 sportbilly 1.4.2.18             }
297 sportbilly 1.4.2.18             public String toString() { return hce.toString(); }
298 sportbilly 1.4.2.18         }
299 sportbilly 1.4.2.18         /** Synthetic edge; either capping or connecting Synthetic 
300 sportbilly 1.4.2.18          *  START or END nodes to each other or to real root/leaves. */
301 sportbilly 1.4.2.18         class FakeEdge extends Edge {
302 sportbilly 1.4.2.18             final Node from, to;
303 sportbilly 1.4.2.18             FakeEdge(Node from, Node to) {
304 cananian   1.6.2.1                  assert from!=null && to !=null;
305 sportbilly 1.4.2.18                 this.from = from; this.to = to;
306 sportbilly 1.4.2.18             }
307 sportbilly 1.4.2.18             public Node otherEnd(Node n) {
308 sportbilly 1.4.2.18                 return from.equals(n)?to:from;
309 sportbilly 1.4.2.18             }
310 sportbilly 1.4.2.18             public String toString() {
311 sportbilly 1.4.2.18                 return "Fake: "+from+" -> "+to;
312 sportbilly 1.4.2.18             }
313 sportbilly 1.4.2.18         }
314 sportbilly 1.4.2.18 
315 sportbilly 1.4.2.18         /*--------------- Utility classes ----------------*/
316 sportbilly 1.4.2.18         /** Singly-linked lists of edges. */
317 sportbilly 1.4.2.18         static class EdgeSList {
318 sportbilly 1.4.2.18             final Edge e;
319 sportbilly 1.4.2.18             final EdgeSList next;
320 sportbilly 1.4.2.18             EdgeSList(Edge e, EdgeSList next) {
321 sportbilly 1.4.2.18                 this.e = e; this.next = next;
322 sportbilly 1.4.2.18             }
323 sportbilly 1.4.2.18         }
324 sportbilly 1.4.2.18         /** Doubly-linked lists of edges. */
325 sportbilly 1.4.2.18         static class EdgeDList {
326 sportbilly 1.4.2.18             final Edge e;
327 sportbilly 1.4.2.18             EdgeDList prev, next;
328 sportbilly 1.4.2.18             EdgeDList(EdgeDList prev, Edge e, EdgeDList next) {
329 sportbilly 1.4.2.18                 this.prev = prev; this.e = e; this.next = next;
330 sportbilly 1.4.2.18             }
331 sportbilly 1.4.2.18         }
332 sportbilly 1.4.2.18         /** BracketList structure, based on doubly-linked edge list. */
333 sportbilly 1.4.2.18         static class BracketList {
334 sportbilly 1.4.2.18             EdgeDList first = null;
335 sportbilly 1.4.2.18             EdgeDList last = null;
336 sportbilly 1.4.2.18             int size = 0;
337 sportbilly 1.4.2.18             
338 sportbilly 1.4.2.18             public BracketList() { }
339 sportbilly 1.4.2.18             public int size() { return size; }
340 sportbilly 1.4.2.18             public void push(Edge e) {
341 sportbilly 1.4.2.18                 first = new EdgeDList(null, e, first);
342 sportbilly 1.4.2.18                 if (first.next!=null)
343 sportbilly 1.4.2.18                     first.next.prev = first;
344 sportbilly 1.4.2.18                 else
345 sportbilly 1.4.2.18                     last = first;
346 sportbilly 1.4.2.18                 e.container = first;
347 sportbilly 1.4.2.18                 size++;
348 sportbilly 1.4.2.18             }
349 sportbilly 1.4.2.18             public Edge top() { return first.e; }
350 sportbilly 1.4.2.18             public void delete(Edge e) {
351 sportbilly 1.4.2.18                 delete(e.container);
352 sportbilly 1.4.2.18             }
353 sportbilly 1.4.2.18             private void delete(EdgeDList el) {
354 sportbilly 1.4.2.18                 if (first==el) first=el.next;
355 sportbilly 1.4.2.18                 else el.prev.next = el.next;
356 sportbilly 1.4.2.18                 if (last==el) last = el.prev;
357 sportbilly 1.4.2.18                 else el.next.prev = el.prev;
358 sportbilly 1.4.2.18                 size--;
359 sportbilly 1.4.2.18             }
360 sportbilly 1.4.2.18             public void append(BracketList bl) {
361 sportbilly 1.4.2.18                 if (bl.first!=null) {
362 sportbilly 1.4.2.18                     if (first==null) {
363 sportbilly 1.4.2.18                         first=bl.first;
364 sportbilly 1.4.2.18                     } else { // this and that both length > 0.
365 sportbilly 1.4.2.18                         last.next = bl.first;
366 sportbilly 1.4.2.18                         bl.first.prev=last;
367 cananian   1.4.2.4                      }
368 sportbilly 1.4.2.18                     last = bl.last;
369 cananian   1.1                      }
370 sportbilly 1.4.2.18                 size += bl.size;
371 sportbilly 1.4.2.18                 // invalidate the source bracket-list.
372 sportbilly 1.4.2.18                 bl.first=bl.last=null; bl.size=0;
373 sportbilly 1.4.2.18             }
374 sportbilly 1.4.2.18             public String toString() {
375 sportbilly 1.4.2.18                 StringBuffer sb=new StringBuffer();
376 sportbilly 1.4.2.18                 sb.append(size);
377 sportbilly 1.4.2.18                 sb.append(": { ");
378 sportbilly 1.4.2.18                 for (EdgeDList el=first; el!=null; el=el.next) {
379 sportbilly 1.4.2.18                     sb.append(el.e);
380 sportbilly 1.4.2.18                     if (el.next!=null)
381 sportbilly 1.4.2.18                         sb.append(", ");
382 cananian   1.1                      }
383 sportbilly 1.4.2.18                 sb.append(" }");
384 sportbilly 1.4.2.18                 return sb.toString();
385 cananian   1.1                  }
386 sportbilly 1.4.2.18         } /* end class BracketList */
387 sportbilly 1.4.2.18     } /* end class Graph */
388 cananian   1.1      }