KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > util > WeakHashSet


1 /*******************************************************************************
2  * Copyright (c) 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.compiler.util;
12 import java.lang.ref.ReferenceQueue JavaDoc;
13 import java.lang.ref.WeakReference JavaDoc;
14
15 /**
16  * A hashset whose values can be garbage collected.
17  */

18 public class WeakHashSet {
19     
20     public class HashableWeakReference extends WeakReference JavaDoc {
21         public int hashCode;
22         public HashableWeakReference(Object JavaDoc referent, ReferenceQueue JavaDoc queue) {
23             super(referent, queue);
24             this.hashCode = referent.hashCode();
25         }
26         public boolean equals(Object JavaDoc obj) {
27             if (!(obj instanceof HashableWeakReference)) return false;
28             Object JavaDoc referent = get();
29             Object JavaDoc other = ((HashableWeakReference) obj).get();
30             if (referent == null) return other == null;
31             return referent.equals(other);
32         }
33         public int hashCode() {
34             return this.hashCode;
35         }
36         public String JavaDoc toString() {
37             Object JavaDoc referent = get();
38             if (referent == null) return "[hashCode=" + this.hashCode + "] <referent was garbage collected>"; //$NON-NLS-1$ //$NON-NLS-2$
39
return "[hashCode=" + this.hashCode + "] " + referent.toString(); //$NON-NLS-1$ //$NON-NLS-2$
40
}
41     }
42     
43     HashableWeakReference[] values;
44     public int elementSize; // number of elements in the table
45
int threshold;
46     ReferenceQueue JavaDoc referenceQueue = new ReferenceQueue JavaDoc();
47     
48     public WeakHashSet() {
49         this(5);
50     }
51     
52     public WeakHashSet(int size) {
53         this.elementSize = 0;
54         this.threshold = size; // size represents the expected number of elements
55
int extraRoom = (int) (size * 1.75f);
56         if (this.threshold == extraRoom)
57             extraRoom++;
58         this.values = new HashableWeakReference[extraRoom];
59     }
60     
61     /*
62      * Adds the given object to this set.
63      * If an object that is equals to the given object already exists, do nothing.
64      * Returns the existing object or the new object if not found.
65      */

66     public Object JavaDoc add(Object JavaDoc obj) {
67         cleanupGarbageCollectedValues();
68         int index = (obj.hashCode() & 0x7FFFFFFF) % this.values.length;
69         HashableWeakReference currentValue;
70         while ((currentValue = this.values[index]) != null) {
71             Object JavaDoc referent;
72             if (obj.equals(referent = currentValue.get())) {
73                 return referent;
74             }
75             index = (index + 1) % this.values.length;
76         }
77         this.values[index] = new HashableWeakReference(obj, this.referenceQueue);
78
79         // assumes the threshold is never equal to the size of the table
80
if (++this.elementSize > this.threshold)
81             rehash();
82         
83         return obj;
84     }
85         
86     private void addValue(HashableWeakReference value) {
87         Object JavaDoc obj = value.get();
88         if (obj == null) return;
89         int valuesLength = this.values.length;
90         int index = (value.hashCode & 0x7FFFFFFF) % valuesLength;
91         HashableWeakReference currentValue;
92         while ((currentValue = this.values[index]) != null) {
93             if (obj.equals(currentValue.get())) {
94                 return;
95             }
96             index = (index + 1) % valuesLength;
97         }
98         this.values[index] = value;
99
100         // assumes the threshold is never equal to the size of the table
101
if (++this.elementSize > this.threshold)
102             rehash();
103     }
104     
105     private void cleanupGarbageCollectedValues() {
106         HashableWeakReference toBeRemoved;
107         while ((toBeRemoved = (HashableWeakReference) this.referenceQueue.poll()) != null) {
108             int hashCode = toBeRemoved.hashCode;
109             int valuesLength = this.values.length;
110             int index = (hashCode & 0x7FFFFFFF) % valuesLength;
111             HashableWeakReference currentValue;
112             while ((currentValue = this.values[index]) != null) {
113                 if (currentValue == toBeRemoved) {
114                     // replace the value at index with the last value with the same hash
115
int sameHash = index;
116                     int current;
117                     while ((currentValue = this.values[current = (sameHash + 1) % valuesLength]) != null && currentValue.hashCode == hashCode)
118                         sameHash = current;
119                     this.values[index] = this.values[sameHash];
120                     this.values[sameHash] = null;
121                     this.elementSize--;
122                     break;
123                 }
124                 index = (index + 1) % valuesLength;
125             }
126         }
127     }
128     
129     public boolean contains(Object JavaDoc obj) {
130         return get(obj) != null;
131     }
132     
133     /*
134      * Return the object that is in this set and that is equals to the given object.
135      * Return null if not found.
136      */

137     public Object JavaDoc get(Object JavaDoc obj) {
138         cleanupGarbageCollectedValues();
139         int valuesLength = this.values.length;
140         int index = (obj.hashCode() & 0x7FFFFFFF) % valuesLength;
141         HashableWeakReference currentValue;
142         while ((currentValue = this.values[index]) != null) {
143             Object JavaDoc referent;
144             if (obj.equals(referent = currentValue.get())) {
145                 return referent;
146             }
147             index = (index + 1) % valuesLength;
148         }
149         return null;
150     }
151         
152     private void rehash() {
153         WeakHashSet newHashSet = new WeakHashSet(this.elementSize * 2); // double the number of expected elements
154
newHashSet.referenceQueue = this.referenceQueue;
155         HashableWeakReference currentValue;
156         for (int i = 0, length = this.values.length; i < length; i++)
157             if ((currentValue = this.values[i]) != null)
158                 newHashSet.addValue(currentValue);
159
160         this.values = newHashSet.values;
161         this.threshold = newHashSet.threshold;
162         this.elementSize = newHashSet.elementSize;
163     }
164
165     /*
166      * Removes the object that is in this set and that is equals to the given object.
167      * Return the object that was in the set, or null if not found.
168      */

169     public Object JavaDoc remove(Object JavaDoc obj) {
170         cleanupGarbageCollectedValues();
171         int valuesLength = this.values.length;
172         int index = (obj.hashCode() & 0x7FFFFFFF) % valuesLength;
173         HashableWeakReference currentValue;
174         while ((currentValue = this.values[index]) != null) {
175             Object JavaDoc referent;
176             if (obj.equals(referent = currentValue.get())) {
177                 this.elementSize--;
178                 this.values[index] = null;
179                 rehash();
180                 return referent;
181             }
182             index = (index + 1) % valuesLength;
183         }
184         return null;
185     }
186
187     public int size() {
188         return this.elementSize;
189     }
190
191     public String JavaDoc toString() {
192         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("{"); //$NON-NLS-1$
193
for (int i = 0, length = this.values.length; i < length; i++) {
194             HashableWeakReference value = this.values[i];
195             if (value != null) {
196                 Object JavaDoc ref = value.get();
197                 if (ref != null) {
198                     buffer.append(ref.toString());
199                     buffer.append(", "); //$NON-NLS-1$
200
}
201             }
202         }
203         buffer.append("}"); //$NON-NLS-1$
204
return buffer.toString();
205     }
206 }
207
Popular Tags