1 11 package org.eclipse.jdt.internal.compiler.util; 12 import java.lang.ref.ReferenceQueue ; 13 import java.lang.ref.WeakReference ; 14 15 18 public class WeakHashSet { 19 20 public 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 index = (obj.hashCode() & 0x7FFFFFFF) % this.values.length; 69 HashableWeakReference currentValue; 70 while ((currentValue = this.values[index]) != null) { 71 Object referent; 72 if (obj.equals(referent = currentValue.get())) { 73 return referent; 74 } 75 index = (index + 1) % this.values.length; 76 } 77 this.values[index] = new HashableWeakReference(obj, this.referenceQueue); 78 79 if (++this.elementSize > this.threshold) 81 rehash(); 82 83 return obj; 84 } 85 86 private void addValue(HashableWeakReference value) { 87 Object obj = value.get(); 88 if (obj == null) return; 89 int valuesLength = this.values.length; 90 int index = (value.hashCode & 0x7FFFFFFF) % valuesLength; 91 HashableWeakReference currentValue; 92 while ((currentValue = this.values[index]) != null) { 93 if (obj.equals(currentValue.get())) { 94 return; 95 } 96 index = (index + 1) % valuesLength; 97 } 98 this.values[index] = value; 99 100 if (++this.elementSize > this.threshold) 102 rehash(); 103 } 104 105 private void cleanupGarbageCollectedValues() { 106 HashableWeakReference toBeRemoved; 107 while ((toBeRemoved = (HashableWeakReference) this.referenceQueue.poll()) != null) { 108 int hashCode = toBeRemoved.hashCode; 109 int valuesLength = this.values.length; 110 int index = (hashCode & 0x7FFFFFFF) % valuesLength; 111 HashableWeakReference currentValue; 112 while ((currentValue = this.values[index]) != null) { 113 if (currentValue == toBeRemoved) { 114 int sameHash = index; 116 int current; 117 while ((currentValue = this.values[current = (sameHash + 1) % valuesLength]) != null && currentValue.hashCode == hashCode) 118 sameHash = current; 119 this.values[index] = this.values[sameHash]; 120 this.values[sameHash] = null; 121 this.elementSize--; 122 break; 123 } 124 index = (index + 1) % valuesLength; 125 } 126 } 127 } 128 129 public boolean contains(Object obj) { 130 return get(obj) != null; 131 } 132 133 137 public Object get(Object obj) { 138 cleanupGarbageCollectedValues(); 139 int valuesLength = this.values.length; 140 int index = (obj.hashCode() & 0x7FFFFFFF) % valuesLength; 141 HashableWeakReference currentValue; 142 while ((currentValue = this.values[index]) != null) { 143 Object referent; 144 if (obj.equals(referent = currentValue.get())) { 145 return referent; 146 } 147 index = (index + 1) % valuesLength; 148 } 149 return null; 150 } 151 152 private void rehash() { 153 WeakHashSet newHashSet = new WeakHashSet(this.elementSize * 2); newHashSet.referenceQueue = this.referenceQueue; 155 HashableWeakReference currentValue; 156 for (int i = 0, length = this.values.length; i < length; i++) 157 if ((currentValue = this.values[i]) != null) 158 newHashSet.addValue(currentValue); 159 160 this.values = newHashSet.values; 161 this.threshold = newHashSet.threshold; 162 this.elementSize = newHashSet.elementSize; 163 } 164 165 169 public Object remove(Object obj) { 170 cleanupGarbageCollectedValues(); 171 int valuesLength = this.values.length; 172 int index = (obj.hashCode() & 0x7FFFFFFF) % valuesLength; 173 HashableWeakReference currentValue; 174 while ((currentValue = this.values[index]) != null) { 175 Object referent; 176 if (obj.equals(referent = currentValue.get())) { 177 this.elementSize--; 178 this.values[index] = null; 179 rehash(); 180 return referent; 181 } 182 index = (index + 1) % valuesLength; 183 } 184 return null; 185 } 186 187 public int size() { 188 return this.elementSize; 189 } 190 191 public String toString() { 192 StringBuffer buffer = new StringBuffer ("{"); for (int i = 0, length = this.values.length; i < length; i++) { 194 HashableWeakReference value = this.values[i]; 195 if (value != null) { 196 Object ref = value.get(); 197 if (ref != null) { 198 buffer.append(ref.toString()); 199 buffer.append(", "); } 201 } 202 } 203 buffer.append("}"); return buffer.toString(); 205 } 206 } 207 | Popular Tags |