KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > soot > util > HashChain


1 /* Soot - a J*va Optimization Framework
2  * Copyright (C) 1999 Patrice Pominville
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */

19
20 /*
21  * Modified by the Sable Research Group and others 1997-1999.
22  * See the 'credits' file distributed with Soot for the complete list of
23  * contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
24  */

25
26
27 package soot.util;
28
29 import java.util.*;
30 import soot.*;
31 import java.io.*;
32
33 /** Reference implementation of the Chain interface,
34     using a HashMap as the underlying structure. */

35 public class HashChain extends AbstractCollection
36     implements Chain
37 {
38     private HashMap map = new HashMap();
39     private Object JavaDoc firstItem;
40     private Object JavaDoc lastItem;
41     private long stateCount = 0;
42
43     /** Erases the contents of the current HashChain. */
44     public void clear()
45     {
46         stateCount++;
47         firstItem = lastItem = null;
48         map.clear();
49     }
50
51     public void swapWith(Object JavaDoc out, Object JavaDoc in)
52     {
53         insertBefore(in, out);
54         remove(out);
55     }
56     
57     /** Adds the given object to this HashChain. */
58     public boolean add(Object JavaDoc item)
59     {
60         addLast(item);
61         return true;
62     }
63
64     /** Returns an unbacked list containing the contents of the given Chain. */
65     public static List toList(Chain c)
66     {
67         Iterator it = c.iterator();
68         List list = new ArrayList();
69         
70         while(it.hasNext()) {
71             list.add(it.next());
72         }
73         
74         return list;
75     }
76
77     /** Constructs an empty HashChain. */
78     public HashChain()
79     {
80         firstItem = lastItem = null;
81     }
82
83     public boolean follows(Object JavaDoc someObject, Object JavaDoc someReferenceObject)
84     {
85         Iterator it = iterator(someObject);
86         while(it.hasNext()) {
87
88             if(it.next() == someReferenceObject)
89                 return false;
90         }
91         return true;
92     }
93     
94     public boolean contains(Object JavaDoc o)
95     {
96         return map.containsKey(o);
97     }
98
99     public boolean containsAll(Collection c)
100     {
101         Iterator it = c.iterator();
102         while (it.hasNext())
103             if (!(map.containsKey(it.next())))
104                 return false;
105         
106         return true;
107     }
108     
109     public void insertAfter(Object JavaDoc toInsert, Object JavaDoc point)
110     {
111         if (toInsert == null)
112             throw new RuntimeException JavaDoc("Bad idea! You tried to insert "
113                                        + " a null object into a Chain!");
114
115         if(map.containsKey(toInsert))
116             throw new RuntimeException JavaDoc("Chain already contains object.");
117         stateCount++;
118         Link temp = (Link) map.get(point);
119         
120         Link newLink = temp.insertAfter(toInsert);
121         map.put(toInsert, newLink);
122     }
123
124     public void insertAfter(List toInsert, Object JavaDoc point)
125     {
126         // if the list is null, treat it as an empty list
127
if (toInsert == null)
128             throw new RuntimeException JavaDoc("Warning! You tried to insert "
129                                        + "a null list into a Chain!");
130
131         Object JavaDoc previousPoint = point;
132         Iterator it = toInsert.iterator();
133         while (it.hasNext())
134             {
135                 Object JavaDoc o = it.next();
136                 insertAfter(o, previousPoint);
137                 previousPoint = o;
138             }
139     }
140     
141     public void insertAfter(Chain toInsert, Object JavaDoc point)
142     {
143         // if the list is null, treat it as an empty list
144
if (toInsert == null)
145             throw new RuntimeException JavaDoc("Warning! You tried to insert "
146                                        + "a null list into a Chain!");
147
148         Object JavaDoc previousPoint = point;
149         Iterator it = toInsert.iterator();
150         while (it.hasNext())
151             {
152                 Object JavaDoc o = it.next();
153                 insertAfter(o, previousPoint);
154                 previousPoint = o;
155             }
156     }
157
158     public void insertBefore(Object JavaDoc toInsert, Object JavaDoc point)
159     {
160         if (toInsert == null)
161             throw new RuntimeException JavaDoc("Bad idea! You tried to insert "
162                                        + "a null object into a Chain!");
163
164         if(map.containsKey(toInsert))
165             throw new RuntimeException JavaDoc("Chain already contains object.");
166         stateCount++;
167         Link temp = (Link) map.get(point);
168         
169         Link newLink = temp.insertBefore(toInsert);
170         map.put(toInsert, newLink);
171     }
172     
173     public void insertBefore(List toInsert, Object JavaDoc point)
174     {
175         // if the list is null, treat it as an empty list
176
if (toInsert == null)
177             throw new RuntimeException JavaDoc("Warning! You tried to insert "
178                                        + "a null list into a Chain!");
179
180         Iterator it = toInsert.iterator();
181         while (it.hasNext())
182             {
183                 Object JavaDoc o = it.next();
184                 insertBefore(o, point);
185             }
186     }
187
188     public void insertBefore(Chain toInsert, Object JavaDoc point)
189     {
190         // if the list is null, treat it as an empty list
191
if (toInsert == null)
192             throw new RuntimeException JavaDoc("Warning! You tried to insert "
193                                        + "a null list into a Chain!");
194
195         Iterator it = toInsert.iterator();
196         while (it.hasNext())
197             {
198                 Object JavaDoc o = it.next();
199                 insertBefore(o, point);
200             }
201     }
202
203     public static HashChain listToHashChain(List list) {
204         HashChain c = new HashChain();
205         Iterator it = list.iterator();
206         while (it.hasNext())
207             c.addLast(it.next());
208         return c;
209     }
210   
211     public boolean remove(Object JavaDoc item)
212     {
213         if (item == null)
214             throw new RuntimeException JavaDoc("Bad idea! You tried to remove "
215                                        + " a null object from a Chain!");
216
217         stateCount++;
218         Link link = (Link) map.get(item);
219         
220         link.unlinkSelf();
221         map.remove(item);
222         return true;
223     }
224
225     public void addFirst(Object JavaDoc item)
226     {
227         if (item == null)
228             throw new RuntimeException JavaDoc("Bad idea! You tried to insert "
229                                        + "a null object into a Chain!");
230
231         stateCount++;
232         Link newLink, temp;
233
234         if(map.containsKey(item))
235             throw new RuntimeException JavaDoc("Chain already contains object.");
236
237         if(firstItem != null) {
238             temp = (Link) map.get(firstItem);
239             newLink = temp.insertBefore(item);
240         } else {
241             newLink = new Link(item);
242             firstItem = lastItem = item;
243         }
244         map.put(item, newLink);
245     }
246
247     public void addLast(Object JavaDoc item)
248     {
249         if (item == null)
250             throw new RuntimeException JavaDoc("Bad idea! You tried to insert "
251                                        + " a null object into a Chain!");
252
253         stateCount++;
254         Link newLink, temp;
255         if(map.containsKey(item))
256             throw new RuntimeException JavaDoc("Chain already contains object: "
257                                        + item);
258         
259         if(lastItem != null) {
260             temp = (Link) map.get(lastItem);
261             newLink = temp.insertAfter(item);
262         } else {
263             newLink = new Link(item);
264             firstItem = lastItem = item;
265         }
266         map.put(item, newLink);
267     }
268     
269     public void removeFirst()
270     {
271         stateCount++;
272         Object JavaDoc item = firstItem;
273         ((Link) map.get(firstItem)).unlinkSelf();
274         map.remove(item);
275     }
276
277     public void removeLast()
278     {
279         stateCount++;
280         Object JavaDoc item = lastItem;
281         ((Link) map.get(lastItem)).unlinkSelf();
282         map.remove(item);
283     }
284
285     public Object JavaDoc getFirst()
286     {
287         if(firstItem == null)
288             throw new NoSuchElementException();
289         return firstItem;
290     }
291     
292     public Object JavaDoc getLast()
293     {
294         if(lastItem == null)
295             throw new NoSuchElementException();
296         return lastItem;
297     }
298
299     public Object JavaDoc getSuccOf(Object JavaDoc point)
300         throws NoSuchElementException
301     {
302         Link link = (Link) map.get(point);
303         try {
304             link = link.getNext();
305         }
306         catch (NullPointerException JavaDoc e) {
307             throw new NoSuchElementException();
308         }
309         if(link == null)
310             return null;
311         
312         return link.getItem();
313     }
314     
315     public Object JavaDoc getPredOf(Object JavaDoc point)
316         throws NoSuchElementException
317     {
318         Link link = (Link) map.get(point);
319         if(point == null)
320             throw new RuntimeException JavaDoc("trying to hash null value.");
321
322         try {
323             link = link.getPrevious();
324         }
325         catch (NullPointerException JavaDoc e) {
326             throw new NoSuchElementException();
327         }
328         
329         if(link == null)
330             return null;
331         else
332             return link.getItem();
333     }
334     
335     public Iterator snapshotIterator()
336     {
337     List l = new ArrayList( map.size());
338     
339     l.addAll(this);
340
341         return l.iterator();
342     }
343    
344     public Iterator snapshotIterator( Object JavaDoc item)
345     {
346         List l = new ArrayList( map.size());
347     
348         Iterator it = new LinkIterator( item);
349         while (it.hasNext())
350             l.add( it.next());
351     
352         return l.iterator();
353     }
354
355     public Iterator iterator(){ return new LinkIterator(firstItem); }
356     public Iterator iterator(Object JavaDoc item)
357     {
358         return new LinkIterator(item);
359     }
360
361     /** <p>Returns an iterator ranging from <code>head</code> to
362      * <code>tail</code>, inclusive.</p>
363
364         <p>If <code>tail</code> is the element immediately preceding
365         <code>head</code> in this <code>HashChain</code>, the returned
366         iterator will iterate 0 times (a special case to allow the
367         specification of an empty range of elements). Otherwise if
368         <code>tail</code> is not one of the elements following
369         <code>head</code>, the returned iterator will iterate past the
370         end of the <code>HashChain</code>, provoking a
371         {@link NoSuchElementException}.</p>
372
373     @throws NoSuchElementException if <code>head</code> is not
374     an element of the chain.
375      */

376     public Iterator iterator(Object JavaDoc head, Object JavaDoc tail)
377     {
378     if (head != null && this.getPredOf(head) == tail) {
379         // special case hack, so empty ranges iterate 0 times
380
return new LinkIterator(null, null);
381     } else {
382         return new LinkIterator(head, tail);
383     }
384     }
385
386     public int size(){ return map.size(); }
387
388     /** Returns a textual representation of the contents of this Chain. */
389     public String JavaDoc toString()
390     {
391         StringBuffer JavaDoc strBuf = new StringBuffer JavaDoc();
392         Iterator it = iterator();
393         boolean b = false;
394
395         strBuf.append("[");
396         while(it.hasNext()) {
397             if (!b) b = true; else strBuf.append(", ");
398             strBuf.append(it.next().toString());
399         }
400         strBuf.append("]");
401         return strBuf.toString();
402     }
403     
404
405     class Link implements Serializable {
406         private Link nextLink;
407         private Link previousLink;
408         private Object JavaDoc item;
409         private int index;
410         
411         public Link(Object JavaDoc item)
412         {
413             this.item = item;
414             nextLink = previousLink = null;
415         }
416
417         public Link getNext() { return nextLink;}
418         public Link getPrevious() { return previousLink;}
419
420         public void setNext(Link link) { this.nextLink = link;}
421         public void setPrevious(Link link) { this.previousLink = link;}
422
423         
424         public void unlinkSelf()
425         {
426             bind(previousLink, nextLink);
427             
428         }
429
430         public Link insertAfter(Object JavaDoc item)
431         {
432             Link newLink = new Link(item);
433             
434             bind(newLink, nextLink);
435             bind(this, newLink);
436             return newLink;
437         }
438         
439         public Link insertBefore(Object JavaDoc item)
440         {
441             Link newLink = new Link(item);
442             
443             bind(previousLink, newLink);
444             bind(newLink, this);
445             return newLink;
446         }
447         
448
449         private void bind(Link a, Link b)
450         {
451             if(a == null) {
452                 if(b != null)
453                     firstItem = b.getItem();
454                 else
455                     firstItem = null;
456             } else
457                 a.setNext(b);
458           
459             if(b == null){
460                 if(a != null)
461                     lastItem = a.getItem();
462                 else
463                     lastItem = null;
464             }
465             else
466                 b.setPrevious(a);
467         }
468
469         public Object JavaDoc getItem() { return item; }
470
471
472         public String JavaDoc toString()
473         {
474             if(item != null)
475                 return item.toString();
476             else
477                 return "Link item is null" + super.toString();
478
479         }
480     
481     }
482
483     class LinkIterator implements Iterator
484     {
485         private Link currentLink;
486         boolean state; // only when this is true can remove() be called
487
// (in accordance w/ iterator semantics)
488

489         private Object JavaDoc destination;
490         private long iteratorStateCount;
491
492
493         public LinkIterator(Object JavaDoc item)
494         {
495         Link nextLink = (Link) map.get(item);
496         if (nextLink == null && item != null)
497         throw new NoSuchElementException("HashChain.LinkIterator(obj) with obj that is not in the chain: " + item.toString() );
498             currentLink = new Link(null);
499             currentLink.setNext(nextLink);
500             state = false;
501             destination = null;
502             iteratorStateCount = stateCount;
503         }
504
505         public LinkIterator(Object JavaDoc from, Object JavaDoc to)
506         {
507             this(from);
508             destination = to;
509         }
510
511             
512         public boolean hasNext()
513         {
514             if(stateCount != iteratorStateCount) {
515                 throw new ConcurrentModificationException();
516             }
517
518         if(destination == null)
519         return (currentLink.getNext() != null);
520         else
521         // Ignore whether (currentLink.getNext() == null), so
522
// next() will produce a NoSuchElementException if
523
// destination is not in the chain.
524
return (destination != currentLink.getItem());
525         }
526             
527         public Object JavaDoc next()
528             throws NoSuchElementException
529         {
530             if(stateCount != iteratorStateCount)
531                 throw new ConcurrentModificationException();
532                         
533             Link temp = currentLink.getNext();
534             if(temp == null) {
535         String JavaDoc exceptionMsg;
536         if(destination != null && destination != currentLink.getItem())
537             exceptionMsg = "HashChain.LinkIterator.next() reached end of chain without reaching specified tail unit";
538             else
539             exceptionMsg = "HashChain.LinkIterator.next() called past the end of the Chain";
540                 throw new NoSuchElementException(exceptionMsg);
541         }
542             currentLink = temp;
543
544             state = true;
545             return currentLink.getItem();
546         }
547
548         public void remove()
549             throws IllegalStateException JavaDoc
550         {
551             if(stateCount != iteratorStateCount)
552                 throw new ConcurrentModificationException();
553             
554             stateCount++; iteratorStateCount++;
555             if(!state)
556                 throw new IllegalStateException JavaDoc();
557             else {
558                 currentLink.unlinkSelf();
559                 map.remove(currentLink.getItem());
560                 state = false;
561             }
562
563         }
564    
565         public String JavaDoc toString()
566         {
567             if(currentLink == null)
568                 return "Current object under iterator is null"
569                     + super.toString();
570             else
571                 return currentLink.toString();
572         }
573     }
574 }
575
576
Popular Tags