1 11 package org.eclipse.jdt.internal.core.util; 12 import java.lang.ref.ReferenceQueue ; 13 import java.lang.ref.WeakReference ; 14 15 18 public class WeakHashSet { 19 20 public static class HashableWeakReference extends WeakReference { 21 public int hashCode; 22 public HashableWeakReference(Object referent, ReferenceQueue queue) { 23 super(referent, queue); 24 this.hashCode = referent.hashCode(); 25 } 26 public boolean equals(Object obj) { 27 if (!(obj instanceof HashableWeakReference)) return false; 28 Object referent = get(); 29 Object 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 toString() { 37 Object referent = get(); 38 if (referent == null) return "[hashCode=" + this.hashCode + "] <referent was garbage collected>"; return "[hashCode=" + this.hashCode + "] " + referent.toString(); } 41 } 42 43 HashableWeakReference[] values; 44 public int elementSize; int threshold; 46 ReferenceQueue referenceQueue = new ReferenceQueue (); 47 48 public WeakHashSet() { 49 this(5); 50 } 51 52 public WeakHashSet(int size) { 53 this.elementSize = 0; 54 this.threshold = size; int extraRoom = (int) (size * 1.75f); 56 if (this.threshold == extraRoom) 57 extraRoom++; 58 this.values = new HashableWeakReference[extraRoom]; 59 } 60 61 66 public Object add(Object 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 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 if (++this.elementSize > this.threshold) 84 rehash(); 85 86 return obj; 87 } 88 89 private void addValue(HashableWeakReference value) { 90 Object 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 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 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 obj) { 137 return get(obj) != null; 138 } 139 140 144 public Object get(Object 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 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); 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 178 public Object remove(Object 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 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 toString() { 203 StringBuffer buffer = new StringBuffer ("{"); for (int i = 0, length = this.values.length; i < length; i++) { 205 HashableWeakReference value = this.values[i]; 206 if (value != null) { 207 Object ref = value.get(); 208 if (ref != null) { 209 buffer.append(ref.toString()); 210 buffer.append(", "); } 212 } 213 } 214 buffer.append("}"); return buffer.toString(); 216 } 217 } 218 | Popular Tags |