KickJava   Java API By Example, From Geeks To Geeks.

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


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 import org.eclipse.jdt.core.compiler.CharOperation;
16
17 /**
18  * A hashset of char[] whose values can be garbage collected.
19  */

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

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

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

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