1 22 23 package org.jboss.util.collection; 24 25 26 import java.lang.ref.WeakReference ; 27 import java.lang.ref.ReferenceQueue ; 28 import java.util.*; 29 30 49 public class WeakIdentityHashMap implements Map { 50 51 54 private static final int DEFAULT_INITIAL_CAPACITY = 16; 55 56 61 private static final int MAXIMUM_CAPACITY = 1 << 30; 62 63 66 private static final float DEFAULT_LOAD_FACTOR = 0.75f; 67 68 71 private Entry[] table; 72 73 76 private int size; 77 78 81 private int threshold; 82 83 86 private final float loadFactor; 87 88 91 private final ReferenceQueue queue = new ReferenceQueue (); 92 93 100 private volatile int modCount; 101 102 107 transient volatile Set keySet = null; 108 transient volatile Collection values = null; 109 110 121 public WeakIdentityHashMap(int initialCapacity, float loadFactor) { 122 if (initialCapacity < 0) 123 throw new IllegalArgumentException ("Illegal Initial Capacity: "+ 124 initialCapacity); 125 if (initialCapacity > MAXIMUM_CAPACITY) 126 initialCapacity = MAXIMUM_CAPACITY; 127 128 if (loadFactor <= 0 || Float.isNaN(loadFactor)) 129 throw new IllegalArgumentException ("Illegal Load factor: "+ 130 loadFactor); 131 int capacity = 1; 132 while (capacity < initialCapacity) 133 capacity <<= 1; 134 table = new Entry[capacity]; 135 this.loadFactor = loadFactor; 136 threshold = (int)(capacity * loadFactor); 137 } 138 139 147 public WeakIdentityHashMap(int initialCapacity) { 148 this(initialCapacity, DEFAULT_LOAD_FACTOR); 149 } 150 151 155 public WeakIdentityHashMap() { 156 this.loadFactor = DEFAULT_LOAD_FACTOR; 157 threshold = (int)(DEFAULT_INITIAL_CAPACITY); 158 table = new Entry[DEFAULT_INITIAL_CAPACITY]; 159 } 160 161 170 public WeakIdentityHashMap(Map t) { 171 this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1, 16), 172 DEFAULT_LOAD_FACTOR); 173 putAll(t); 174 } 175 176 178 181 private static final Object NULL_KEY = new Object (); 182 183 186 private static Object maskNull(Object key) { 187 return (key == null ? NULL_KEY : key); 188 } 189 190 193 private static Object unmaskNull(Object key) { 194 return (key == NULL_KEY ? null : key); 195 } 196 197 200 int hash(Object x) { 201 int h = System.identityHashCode(x); 202 return h - (h << 7); } 204 205 208 static int indexFor(int h, int length) { 209 return h & (length-1); 210 } 211 212 215 private void expungeStaleEntries() { 216 Object r; 217 while ( (r = queue.poll()) != null) { 218 Entry e = (Entry)r; 219 int h = e.hash; 220 int i = indexFor(h, table.length); 221 222 Entry prev = table[i]; 223 Entry p = prev; 224 while (p != null) { 225 Entry next = p.next; 226 if (p == e) { 227 if (prev == e) 228 table[i] = next; 229 else 230 prev.next = next; 231 e.next = null; e.value = null; size--; 234 break; 235 } 236 prev = p; 237 p = next; 238 } 239 } 240 } 241 242 245 private Entry[] getTable() { 246 expungeStaleEntries(); 247 return table; 248 } 249 250 256 public int size() { 257 if (size == 0) 258 return 0; 259 expungeStaleEntries(); 260 return size; 261 } 262 263 269 public boolean isEmpty() { 270 return size() == 0; 271 } 272 273 287 public Object get(Object key) { 288 Object k = maskNull(key); 289 int h = hash(k); 290 Entry[] tab = getTable(); 291 int index = indexFor(h, tab.length); 292 Entry e = tab[index]; 293 while (e != null) { 294 if (e.hash == h && k == e.get()) 295 return e.value; 296 e = e.next; 297 } 298 return null; 299 } 300 301 309 public boolean containsKey(Object key) { 310 return getEntry(key) != null; 311 } 312 313 317 Entry getEntry(Object key) { 318 Object k = maskNull(key); 319 int h = hash(k); 320 Entry[] tab = getTable(); 321 int index = indexFor(h, tab.length); 322 Entry e = tab[index]; 323 while (e != null && !(e.hash == h && k == e.get())) 324 e = e.next; 325 return e; 326 } 327 328 340 public Object put(Object key, Object value) { 341 Object k = maskNull(key); 342 int h = hash(k); 343 Entry[] tab = getTable(); 344 int i = indexFor(h, tab.length); 345 346 for (Entry e = tab[i]; e != null; e = e.next) { 347 if (h == e.hash && k == e.get()) { 348 Object oldValue = e.value; 349 if (value != oldValue) 350 e.value = value; 351 return oldValue; 352 } 353 } 354 355 modCount++; 356 tab[i] = new Entry(k, value, queue, h, tab[i]); 357 if (++size >= threshold) 358 resize(tab.length * 2); 359 return null; 360 } 361 362 372 void resize(int newCapacity) { 373 375 Entry[] oldTable = getTable(); 376 int oldCapacity = oldTable.length; 377 378 if (size < threshold || oldCapacity > newCapacity) 380 return; 381 382 Entry[] newTable = new Entry[newCapacity]; 383 384 transfer(oldTable, newTable); 385 table = newTable; 386 387 392 if (size >= threshold / 2) { 393 threshold = (int)(newCapacity * loadFactor); 394 } else { 395 expungeStaleEntries(); 396 transfer(newTable, oldTable); 397 table = oldTable; 398 } 399 } 400 401 402 private void transfer(Entry[] src, Entry[] dest) { 403 for (int j = 0; j < src.length; ++j) { 404 Entry e = src[j]; 405 src[j] = null; 406 while (e != null) { 407 Entry next = e.next; 408 Object key = e.get(); 409 if (key == null) { 410 e.next = null; e.value = null; size--; 413 } else { 414 int i = indexFor(e.hash, dest.length); 415 e.next = dest[i]; 416 dest[i] = e; 417 } 418 e = next; 419 } 420 } 421 } 422 423 431 public void putAll(Map t) { 432 int n = t.size(); 434 if (n == 0) 435 return; 436 if (n >= threshold) { 437 n = (int)(n / loadFactor + 1); 438 if (n > MAXIMUM_CAPACITY) 439 n = MAXIMUM_CAPACITY; 440 int capacity = table.length; 441 while (capacity < n) 442 capacity <<= 1; 443 resize(capacity); 444 } 445 446 for (Iterator i = t.entrySet().iterator(); i.hasNext(); ) { 447 Map.Entry e = (Map.Entry) i.next(); 448 put(e.getKey(), e.getValue()); 449 } 450 } 451 452 461 public Object remove(Object key) { 462 Object k = maskNull(key); 463 int h = hash(k); 464 Entry[] tab = getTable(); 465 int i = indexFor(h, tab.length); 466 Entry prev = tab[i]; 467 Entry e = prev; 468 469 while (e != null) { 470 Entry next = e.next; 471 if (h == e.hash && k == e.get()) { 472 modCount++; 473 size--; 474 if (prev == e) 475 tab[i] = next; 476 else 477 prev.next = next; 478 return e.value; 479 } 480 prev = e; 481 e = next; 482 } 483 484 return null; 485 } 486 487 488 489 490 Entry removeMapping(Object o) { 491 if (!(o instanceof Map.Entry)) 492 return null; 493 Entry[] tab = getTable(); 494 Map.Entry entry = (Map.Entry)o; 495 Object k = maskNull(entry.getKey()); 496 int h = hash(k); 497 int i = indexFor(h, tab.length); 498 Entry prev = tab[i]; 499 Entry e = prev; 500 501 while (e != null) { 502 Entry next = e.next; 503 if (h == e.hash && e.equals(entry)) { 504 modCount++; 505 size--; 506 if (prev == e) 507 tab[i] = next; 508 else 509 prev.next = next; 510 return e; 511 } 512 prev = e; 513 e = next; 514 } 515 516 return null; 517 } 518 519 522 public void clear() { 523 while (queue.poll() != null) 526 ; 527 528 modCount++; 529 Entry tab[] = table; 530 for (int i = 0; i < tab.length; ++i) 531 tab[i] = null; 532 size = 0; 533 534 while (queue.poll() != null) 538 ; 539 } 540 541 549 public boolean containsValue(Object value) { 550 if (value==null) 551 return containsNullValue(); 552 553 Entry tab[] = getTable(); 554 for (int i = tab.length ; i-- > 0 ;) 555 for (Entry e = tab[i] ; e != null ; e = e.next) 556 if (value.equals(e.value)) 557 return true; 558 return false; 559 } 560 561 564 private boolean containsNullValue() { 565 Entry tab[] = getTable(); 566 for (int i = tab.length ; i-- > 0 ;) 567 for (Entry e = tab[i] ; e != null ; e = e.next) 568 if (e.value==null) 569 return true; 570 return false; 571 } 572 573 577 private static class Entry extends WeakReference implements Map.Entry { 578 private Object value; 579 private final int hash; 580 private Entry next; 581 582 585 Entry(Object key, Object value, ReferenceQueue queue, 586 int hash, Entry next) { 587 super(key, queue); 588 this.value = value; 589 this.hash = hash; 590 this.next = next; 591 } 592 593 public Object getKey() { 594 return unmaskNull(this.get()); 595 } 596 597 public Object getValue() { 598 return value; 599 } 600 601 public Object setValue(Object newValue) { 602 Object oldValue = value; 603 value = newValue; 604 return oldValue; 605 } 606 607 public boolean equals(Object o) { 608 if (!(o instanceof Map.Entry)) 609 return false; 610 Map.Entry e = (Map.Entry)o; 611 Object k1 = getKey(); 612 Object k2 = e.getKey(); 613 if (k1 == k2) { 614 Object v1 = getValue(); 615 Object v2 = e.getValue(); 616 if (v1 == v2 || (v1 != null && v1.equals(v2))) 617 return true; 618 } 619 return false; 620 } 621 622 public int hashCode() { 623 Object k = getKey(); 624 Object v = getValue(); 625 return ((k==null ? 0 : System.identityHashCode(k)) ^ 626 (v==null ? 0 : v.hashCode())); 627 } 628 629 public String toString() { 630 return getKey() + "=" + getValue(); 631 } 632 } 633 634 private abstract class HashIterator implements Iterator { 635 int index; 636 Entry entry = null; 637 Entry lastReturned = null; 638 int expectedModCount = modCount; 639 640 644 Object nextKey = null; 645 646 650 Object currentKey = null; 651 652 HashIterator() { 653 index = (size() != 0 ? table.length : 0); 654 } 655 656 public boolean hasNext() { 657 Entry[] t = table; 658 659 while (nextKey == null) { 660 Entry e = entry; 661 int i = index; 662 while (e == null && i > 0) 663 e = t[--i]; 664 entry = e; 665 index = i; 666 if (e == null) { 667 currentKey = null; 668 return false; 669 } 670 nextKey = e.get(); if (nextKey == null) 672 entry = entry.next; 673 } 674 return true; 675 } 676 677 678 protected Entry nextEntry() { 679 if (modCount != expectedModCount) 680 throw new ConcurrentModificationException(); 681 if (nextKey == null && !hasNext()) 682 throw new NoSuchElementException(); 683 684 lastReturned = entry; 685 entry = entry.next; 686 currentKey = nextKey; 687 nextKey = null; 688 return lastReturned; 689 } 690 691 public void remove() { 692 if (lastReturned == null) 693 throw new IllegalStateException (); 694 if (modCount != expectedModCount) 695 throw new ConcurrentModificationException(); 696 697 WeakIdentityHashMap.this.remove(currentKey); 698 expectedModCount = modCount; 699 lastReturned = null; 700 currentKey = null; 701 } 702 703 } 704 705 private class ValueIterator extends HashIterator { 706 public Object next() { 707 return nextEntry().value; 708 } 709 } 710 711 private class KeyIterator extends HashIterator { 712 public Object next() { 713 return nextEntry().getKey(); 714 } 715 } 716 717 private class EntryIterator extends HashIterator { 718 public Object next() { 719 return nextEntry(); 720 } 721 } 722 723 725 private transient Set entrySet = null; 726 727 738 public Set keySet() { 739 Set ks = keySet; 740 return (ks != null ? ks : (keySet = new KeySet())); 741 } 742 743 private class KeySet extends AbstractSet { 744 public Iterator iterator() { 745 return new KeyIterator(); 746 } 747 748 public int size() { 749 return WeakIdentityHashMap.this.size(); 750 } 751 752 public boolean contains(Object o) { 753 return containsKey(o); 754 } 755 756 public boolean remove(Object o) { 757 if (containsKey(o)) { 758 WeakIdentityHashMap.this.remove(o); 759 return true; 760 } 761 else 762 return false; 763 } 764 765 public void clear() { 766 WeakIdentityHashMap.this.clear(); 767 } 768 769 public Object [] toArray() { 770 Collection c = new ArrayList(size()); 771 for (Iterator i = iterator(); i.hasNext(); ) 772 c.add(i.next()); 773 return c.toArray(); 774 } 775 776 public Object [] toArray(Object a[]) { 777 Collection c = new ArrayList(size()); 778 for (Iterator i = iterator(); i.hasNext(); ) 779 c.add(i.next()); 780 return c.toArray(a); 781 } 782 } 783 784 795 public Collection values() { 796 Collection vs = values; 797 return (vs != null ? vs : (values = new Values())); 798 } 799 800 private class Values extends AbstractCollection { 801 public Iterator iterator() { 802 return new ValueIterator(); 803 } 804 805 public int size() { 806 return WeakIdentityHashMap.this.size(); 807 } 808 809 public boolean contains(Object o) { 810 return containsValue(o); 811 } 812 813 public void clear() { 814 WeakIdentityHashMap.this.clear(); 815 } 816 817 public Object [] toArray() { 818 Collection c = new ArrayList(size()); 819 for (Iterator i = iterator(); i.hasNext(); ) 820 c.add(i.next()); 821 return c.toArray(); 822 } 823 824 public Object [] toArray(Object a[]) { 825 Collection c = new ArrayList(size()); 826 for (Iterator i = iterator(); i.hasNext(); ) 827 c.add(i.next()); 828 return c.toArray(a); 829 } 830 } 831 832 845 public Set entrySet() { 846 Set es = entrySet; 847 return (es != null ? es : (entrySet = new EntrySet())); 848 } 849 850 private class EntrySet extends AbstractSet { 851 public Iterator iterator() { 852 return new EntryIterator(); 853 } 854 855 public boolean contains(Object o) { 856 if (!(o instanceof Map.Entry)) 857 return false; 858 Map.Entry e = (Map.Entry)o; 859 Object k = e.getKey(); 860 Entry candidate = getEntry(e.getKey()); 861 return candidate != null && candidate.equals(e); 862 } 863 864 public boolean remove(Object o) { 865 return removeMapping(o) != null; 866 } 867 868 public int size() { 869 return WeakIdentityHashMap.this.size(); 870 } 871 872 public void clear() { 873 WeakIdentityHashMap.this.clear(); 874 } 875 876 public Object [] toArray() { 877 Collection c = new ArrayList(size()); 878 for (Iterator i = iterator(); i.hasNext(); ) 879 c.add(new SimpleEntry((Map.Entry) i.next())); 880 return c.toArray(); 881 } 882 883 public Object [] toArray(Object a[]) { 884 Collection c = new ArrayList(size()); 885 for (Iterator i = iterator(); i.hasNext(); ) 886 c.add(new SimpleEntry((Map.Entry) i.next())); 887 return c.toArray(a); 888 } 889 } 890 891 static class SimpleEntry implements Map.Entry { 892 Object key; 893 Object value; 894 895 public SimpleEntry(Object key, Object value) { 896 this.key = key; 897 this.value = value; 898 } 899 900 public SimpleEntry(Map.Entry e) { 901 this.key = e.getKey(); 902 this.value = e.getValue(); 903 } 904 905 public Object getKey() { 906 return key; 907 } 908 909 public Object getValue() { 910 return value; 911 } 912 913 public Object setValue(Object value) { 914 Object oldValue = this.value; 915 this.value = value; 916 return oldValue; 917 } 918 919 public boolean equals(Object o) { 920 if (!(o instanceof Map.Entry)) 921 return false; 922 Map.Entry e = (Map.Entry)o; 923 return eq(key, e.getKey()) && eq(value, e.getValue()); 924 } 925 926 public int hashCode() { 927 Object v; 928 return ((key == null) ? 0 : key.hashCode()) ^ 929 ((value == null) ? 0 : value.hashCode()); 930 } 931 932 public String toString() { 933 return key + "=" + value; 934 } 935 936 private static boolean eq(Object o1, Object o2) { 937 return (o1 == null ? o2 == null : o1.equals(o2)); 938 } 939 } 940 941 } 942 943 | Popular Tags |