1 19 20 package org.openide.util; 21 22 import java.io.IOException ; 23 import java.io.ObjectInputStream ; 24 import java.io.ObjectOutputStream ; 25 import java.io.Serializable ; 26 import java.lang.ref.ReferenceQueue ; 27 import java.lang.ref.WeakReference ; 28 import java.util.AbstractSet ; 29 import java.util.ArrayList ; 30 import java.util.Collection ; 31 import java.util.ConcurrentModificationException ; 32 import java.util.Iterator ; 33 34 43 public class WeakSet<E> extends AbstractSet <E> implements Cloneable , Serializable { 44 static final long serialVersionUID = 3062376055928236721L; 45 46 47 private float loadFactor; 48 49 50 private int size; 51 52 53 private long modcount; 54 55 56 private transient ReferenceQueue <E> refq; 57 58 59 long nullCount; 60 61 62 private transient Entry<E>[] entries; 63 transient Entry<E> iterChain; 64 65 66 public WeakSet() { 67 this(11, 0.75f); 68 } 69 70 73 public WeakSet(Collection <? extends E> c) { 74 this(); 75 addAll(c); 76 } 77 78 81 public WeakSet(int initialCapacity) { 82 this(initialCapacity, 0.75f); 83 } 84 85 90 public WeakSet(int initialCapacity, float loadFactor) { 91 if ((initialCapacity <= 0) || (loadFactor <= 0)) { 92 throw new IllegalArgumentException (); 93 } 94 95 size = 0; 96 modcount = 0; 97 this.loadFactor = loadFactor; 98 nullCount = 0; 99 refq = new ReferenceQueue <E>(); 100 entries = Entry.createArray(initialCapacity); 101 iterChain = null; 102 } 103 104 108 public boolean add(E o) { 109 if (o == null) { 110 size++; 111 nullCount++; 112 modcount++; 113 114 return true; 115 } 116 117 Entry e = object2Entry(o); 118 119 if (e != null) { 120 return false; 121 } 122 123 modcount++; 124 size++; 125 126 int hash = hashIt(o); 127 Entry<E> next = entries[hash]; 128 iterChain = entries[hash] = new Entry<E>(this, o, refq, next, iterChain); 129 rehash(); 130 131 return true; 132 } 133 134 135 public void clear() { 136 for (int i = 0; i < entries.length; i++) { 137 entries[i] = null; 138 } 139 140 nullCount = 0; 141 modcount++; 142 size = 0; 143 iterChain = null; 144 } 145 146 147 public Object clone() { 148 WeakSet<E> nws = new WeakSet<E>(1, loadFactor); 149 nws.size = size; 150 nws.nullCount = nullCount; 151 152 Entry<E>[] cloned = Entry.createArray(entries.length); 153 nws.entries = cloned; 154 155 for (int i = 0; i < cloned.length; i++) { 156 Object ref; 157 158 if ((entries[i] == null) || ((ref = entries[i].get()) == null)) { 159 cloned[i] = null; 160 } else { 161 cloned[i] = ((entries[i] == null) ? null : entries[i].clone(nws.refq)); 162 ref = null; 163 } 164 165 Entry<E> entry = cloned[i]; 167 168 while (entry != null) { 169 entry.chainIntoIter(nws.iterChain); 170 nws.iterChain = entry; 171 entry = entry.next; 172 } 173 } 174 175 return nws; 176 } 177 178 182 public boolean contains(Object o) { 183 if (o == null) { 184 return nullCount > 0; 185 } 186 187 return object2Entry(o) != null; 188 } 189 190 192 public boolean isEmpty() { 193 return ((nullCount == 0) && (size() == 0)); 194 } 195 196 197 public Iterator <E> iterator() { 198 return new WeakSetIterator(); 199 } 200 201 206 public boolean remove(Object o) { 207 if (o == null) { 208 if (nullCount > 0) { 209 nullCount--; 210 modcount++; 211 size--; 212 } 213 214 return true; 215 } 216 217 Entry e = object2Entry(o); 218 219 if (e != null) { 220 modcount++; 221 size--; 222 e.remove(); 223 rehash(); 224 225 return true; 226 } 227 228 return false; 229 } 230 231 232 public int size() { 233 checkRefQueue(); 234 235 return size; 236 } 237 238 public <T> T[] toArray(T[] array) { 239 ArrayList <E> list = new ArrayList <E>(array.length); 240 Iterator <E> it = iterator(); 241 242 while (it.hasNext()) { 243 list.add(it.next()); 244 } 245 246 return list.toArray(array); 247 } 248 249 public Object [] toArray() { 250 ArrayList <E> list = new ArrayList <E>(); 251 Iterator <E> it = iterator(); 252 253 while (it.hasNext()) { 254 list.add(it.next()); 255 } 256 257 return list.toArray(); 258 } 259 260 public String toString() { 262 StringBuffer buf = new StringBuffer (); 263 Iterator e = iterator(); 264 buf.append("["); 265 266 while (e.hasNext()) { 267 buf.append(String.valueOf(e.next())); 268 269 if (e.hasNext()) { 270 buf.append(", "); 271 } 272 } 273 274 buf.append("]"); 275 276 return buf.toString(); 277 } 278 279 280 void checkRefQueue() { 281 for (;;) { 282 Entry entry = Entry.class.cast(refq.poll()); 283 284 if (entry == null) { 285 break; 286 } 287 288 entry.remove(); 289 size--; 290 } 291 } 292 293 294 long modCount() { 295 return modcount; 296 } 297 298 299 int hashIt(Object o) { 300 return (o.hashCode() & 0x7fffffff) % entries.length; 301 } 302 303 304 void rehash() { 305 311 } 312 313 314 private Entry object2Entry(Object o) { 315 checkRefQueue(); 317 int hash = hashIt(o); 318 Entry e = entries[hash]; 319 320 if (e == null) { 321 return null; 322 } 323 324 while ((e != null) && !e.equals(o)) { 325 e = e.next; 326 } 327 328 return e; 329 } 330 331 private void writeObject(ObjectOutputStream obtos) 332 throws IOException { 333 obtos.defaultWriteObject(); 334 obtos.writeObject(toArray()); 335 } 336 337 @SuppressWarnings ("unchecked") 338 private void readObject(ObjectInputStream obtis) throws IOException , ClassNotFoundException { 339 obtis.defaultReadObject(); 340 341 Object [] arr = (Object []) obtis.readObject(); 342 entries = new Entry[(int) (size * 1.5)]; 343 refq = new ReferenceQueue <E>(); 344 345 for (int i = 0; i < arr.length; i++) { 346 add((E)arr[i]); 347 } 348 } 349 350 class WeakSetIterator implements Iterator <E> { 351 Entry<E> current; 352 Entry<E> next; 353 E currentObj; 354 E nextObj; 355 final long myModcount; 356 long myNullCount; 357 358 WeakSetIterator() { 359 myModcount = modCount(); 360 myNullCount = nullCount; 361 current = null; 362 next = null; 363 364 Entry<E> ee = iterChain; 365 366 if (ee == null) { 367 return; 368 } 369 370 E o = ee.get(); 371 372 while (ee.isEnqueued()) { 373 ee = ee.iterChainNext; 374 375 if (ee == null) { 376 return; 377 } 378 379 o = ee.get(); 380 } 381 382 nextObj = o; 383 next = ee; 384 } 385 386 public boolean hasNext() { 387 checkModcount(); 388 389 return ((myNullCount > 0) || (next != null)); 390 } 391 392 public E next() { 393 checkModcount(); 394 checkRefQueue(); 395 396 if (myNullCount > 0) { 397 myNullCount--; 398 399 return null; 400 } else { 401 if (next == null) { 402 throw new java.util.NoSuchElementException (); 403 } 404 405 current = next; 406 currentObj = nextObj; 407 408 do { 410 next = next.iterChainNext; 411 412 if (next == null) { 413 break; 414 } 415 416 nextObj = next.get(); 417 } while (next.isEnqueued()); 418 419 return currentObj; 420 } 421 } 422 423 public void remove() { 424 checkModcount(); 425 426 if (current == null) { 427 throw new IllegalStateException (); 428 } 429 430 current.remove(); 431 size--; 432 } 433 434 void checkModcount() { 435 if (myModcount != modCount()) { 436 throw new ConcurrentModificationException (); 437 } 438 } 439 } 440 441 442 static class Entry<E> extends WeakReference <E> { 443 444 private WeakSet<E> set; 445 446 Entry<E> prev; 448 Entry<E> next; 449 private final int hashcode; 450 Entry<E> iterChainNext; 451 Entry<E> iterChainPrev; 452 453 Entry(WeakSet<E> set, E referenced, ReferenceQueue <E> q, Entry<E> next, Entry<E> nextInIter) { 454 super(referenced, q); 455 this.set = set; 456 457 this.next = next; 458 this.prev = null; 459 460 if (next != null) { 461 next.prev = this; 462 } 463 464 if (referenced != null) { 465 hashcode = set.hashIt(referenced); 466 } else { 467 hashcode = 0; 468 } 469 470 chainIntoIter(nextInIter); 471 } 472 473 @SuppressWarnings ("unchecked") 474 static final <E> Entry<E>[] createArray(int size) { 475 return new Entry[size]; 476 } 477 478 void chainIntoIter(Entry<E> nextInIter) { 479 iterChainNext = nextInIter; 480 481 if (nextInIter != null) { 482 nextInIter.iterChainPrev = this; 483 484 Object ref = nextInIter.get(); 485 486 if (ref == null) { 487 nextInIter.remove(); 488 } 489 } 490 } 491 492 493 void remove() { 494 if (prev != null) { 495 prev.next = next; 496 } 497 498 if (next != null) { 499 next.prev = prev; 500 } 501 502 if (iterChainNext != null) { 503 iterChainNext.iterChainPrev = iterChainPrev; 504 } 505 506 if (iterChainPrev != null) { 507 iterChainPrev.iterChainNext = iterChainNext; 508 } else { set.iterChain = iterChainNext; 510 } 511 512 if (set.entries[hashcode] == this) { 513 set.entries[hashcode] = next; 514 } 515 516 prev = null; 517 next = null; 518 iterChainNext = null; 519 iterChainPrev = null; 520 } 521 522 public int hashCode() { 523 return hashcode; 524 } 525 526 public boolean equals(Object o) { 527 Object oo = get(); 528 529 if (oo == null) { 530 return false; 531 } else { 532 return oo.equals(o); 533 } 534 } 535 536 public Entry<E> clone(ReferenceQueue <E> q) { 537 return new Entry<E>(set, get(), q, next != null ? next.clone(q) : null, null); 538 } 539 } 540 } 541 | Popular Tags |