KickJava   Java API By Example, From Geeks To Geeks.

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


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

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

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