1 11 package org.eclipse.core.internal.registry; 12 13 import java.lang.ref.ReferenceQueue ; 14 import java.lang.ref.SoftReference ; 15 import java.lang.ref.WeakReference ; 16 17 22 public class ReferenceHashSet { 23 24 private interface HashedReference { 25 int hashCode(); 26 Object get(); 27 } 28 29 private class HashableWeakReference extends WeakReference implements HashedReference { 30 public int hashCode; 31 32 public HashableWeakReference(Object referent, ReferenceQueue queue) { 33 super(referent, queue); 34 this.hashCode = referent.hashCode(); 35 } 36 37 public boolean equals(Object obj) { 38 if (!(obj instanceof HashableWeakReference)) 39 return false; 40 Object referent = get(); 41 Object other = ((HashableWeakReference) obj).get(); 42 if (referent == null) 43 return other == null; 44 return referent.equals(other); 45 } 46 47 public int hashCode() { 48 return this.hashCode; 49 } 50 51 public String toString() { 52 Object referent = get(); 53 if (referent == null) 54 return "[hashCode=" + this.hashCode + "] <referent was garbage collected>"; return "[hashCode=" + this.hashCode + "] " + referent.toString(); } 57 } 58 59 private class HashableSoftReference extends SoftReference implements HashedReference { 60 public int hashCode; 61 62 public HashableSoftReference(Object referent, ReferenceQueue queue) { 63 super(referent, queue); 64 this.hashCode = referent.hashCode(); 65 } 66 67 public boolean equals(Object obj) { 68 if (!(obj instanceof HashableWeakReference)) 69 return false; 70 Object referent = get(); 71 Object other = ((HashableWeakReference) obj).get(); 72 if (referent == null) 73 return other == null; 74 return referent.equals(other); 75 } 76 77 public int hashCode() { 78 return this.hashCode; 79 } 80 81 public String toString() { 82 Object referent = get(); 83 if (referent == null) 84 return "[hashCode=" + this.hashCode + "] <referent was garbage collected>"; return "[hashCode=" + this.hashCode + "] " + referent.toString(); } 87 } 88 89 private class StrongReference implements HashedReference { 90 private Object referent; 91 92 public StrongReference(Object referent, ReferenceQueue queue) { 93 this.referent = referent; 94 } 95 96 public int hashCode() { 97 return referent.hashCode(); 98 } 99 100 public Object get() { 101 return referent; 102 } 103 104 public boolean equals(Object obj) { 105 return referent.equals(obj); 106 } 107 } 108 109 HashedReference[] values; 110 111 public int elementSize; 113 int threshold; 114 115 ReferenceQueue referenceQueue = new ReferenceQueue (); 116 117 public ReferenceHashSet() { 118 this(5); 119 } 120 121 public ReferenceHashSet(int size) { 122 this.elementSize = 0; 123 this.threshold = size; int extraRoom = (int) (size * 1.75f); 126 if (this.threshold == extraRoom) 127 extraRoom++; 128 this.values = new HashedReference[extraRoom]; 129 } 130 131 134 final public static int HARD = 0; 135 136 139 final public static int SOFT = 1; 140 141 144 final public static int WEAK = 2; 145 146 private HashedReference toReference(int type, Object referent) { 147 switch (type) { 148 case HARD: 149 return new StrongReference(referent, referenceQueue); 150 case SOFT: 151 return new HashableSoftReference(referent, referenceQueue); 152 case WEAK: 153 return new HashableWeakReference(referent, referenceQueue); 154 default: 155 throw new Error (); 156 } 157 } 158 159 164 public Object add(Object obj, int referenceType) { 165 cleanupGarbageCollectedValues(); 166 int index = (obj.hashCode() & 0x7FFFFFFF) % this.values.length; 167 HashedReference currentValue; 168 while ((currentValue = this.values[index]) != null) { 169 Object referent; 170 if (obj.equals(referent = currentValue.get())) { 171 return referent; 172 } 173 index = (index + 1) % this.values.length; 174 } 175 this.values[index] = toReference(referenceType, obj); 176 177 if (++this.elementSize > this.threshold) 179 rehash(); 180 181 return obj; 182 } 183 184 private void addValue(HashedReference value) { 185 Object obj = value.get(); 186 if (obj == null) 187 return; 188 int valuesLength = this.values.length; 189 int index = (value.hashCode() & 0x7FFFFFFF) % valuesLength; 190 HashedReference currentValue; 191 while ((currentValue = this.values[index]) != null) { 192 if (obj.equals(currentValue.get())) { 193 return; 194 } 195 index = (index + 1) % valuesLength; 196 } 197 this.values[index] = value; 198 199 if (++this.elementSize > this.threshold) 201 rehash(); 202 } 203 204 private void cleanupGarbageCollectedValues() { 205 HashedReference toBeRemoved; 206 while ((toBeRemoved = (HashedReference) this.referenceQueue.poll()) != null) { 207 int hashCode = toBeRemoved.hashCode(); 208 int valuesLength = this.values.length; 209 int index = (hashCode & 0x7FFFFFFF) % valuesLength; 210 HashedReference currentValue; 211 while ((currentValue = this.values[index]) != null) { 212 if (currentValue == toBeRemoved) { 213 int sameHash = index; 216 int current; 217 while ((currentValue = this.values[current = (sameHash + 1) % valuesLength]) != null && currentValue.hashCode() == hashCode) 218 sameHash = current; 219 this.values[index] = this.values[sameHash]; 220 this.values[sameHash] = null; 221 this.elementSize--; 222 break; 223 } 224 index = (index + 1) % valuesLength; 225 } 226 } 227 } 228 229 public boolean contains(Object obj) { 230 return get(obj) != null; 231 } 232 233 237 public Object get(Object obj) { 238 cleanupGarbageCollectedValues(); 239 int valuesLength = this.values.length; 240 int index = (obj.hashCode() & 0x7FFFFFFF) % valuesLength; 241 HashedReference currentValue; 242 while ((currentValue = this.values[index]) != null) { 243 Object referent; 244 if (obj.equals(referent = currentValue.get())) { 245 return referent; 246 } 247 index = (index + 1) % valuesLength; 248 } 249 return null; 250 } 251 252 private void rehash() { 253 ReferenceHashSet newHashSet = new ReferenceHashSet(this.elementSize * 2); newHashSet.referenceQueue = this.referenceQueue; 255 HashedReference currentValue; 256 for (int i = 0, length = this.values.length; i < length; i++) 257 if ((currentValue = this.values[i]) != null) 258 newHashSet.addValue(currentValue); 259 260 this.values = newHashSet.values; 261 this.threshold = newHashSet.threshold; 262 this.elementSize = newHashSet.elementSize; 263 } 264 265 269 public Object remove(Object obj) { 270 cleanupGarbageCollectedValues(); 271 int valuesLength = this.values.length; 272 int index = (obj.hashCode() & 0x7FFFFFFF) % valuesLength; 273 HashedReference currentValue; 274 while ((currentValue = this.values[index]) != null) { 275 Object referent; 276 if (obj.equals(referent = currentValue.get())) { 277 this.elementSize--; 278 this.values[index] = null; 279 rehash(); 280 return referent; 281 } 282 index = (index + 1) % valuesLength; 283 } 284 return null; 285 } 286 287 public int size() { 288 return this.elementSize; 289 } 290 291 public String toString() { 292 StringBuffer buffer = new StringBuffer ("{"); for (int i = 0, length = this.values.length; i < length; i++) { 294 HashedReference value = this.values[i]; 295 if (value != null) { 296 Object ref = value.get(); 297 if (ref != null) { 298 buffer.append(ref.toString()); 299 buffer.append(", "); } 301 } 302 } 303 buffer.append("}"); return buffer.toString(); 305 } 306 307 public Object [] toArray() { 308 cleanupGarbageCollectedValues(); 309 Object [] result = new Object [elementSize]; 310 int resultSize = 0; 311 for (int i = 0; i < values.length; i++) { 312 if (values[i] == null) 313 continue; 314 Object tmp = values[i].get(); 315 if (tmp != null) 316 result[resultSize++] = tmp; 317 } 318 if (result.length == resultSize) 319 return result; 320 Object [] finalResult = new Object [resultSize]; 321 System.arraycopy(result, 0, finalResult, 0, resultSize); 322 return finalResult; 323 } 324 } 325 | Popular Tags |