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