1 52 53 package com.go.trove.util; 54 55 import java.lang.ref.*; 56 import java.util.*; 57 58 89 public class IdentityMap extends AbstractMap implements Map, Cloneable { 90 static final int KEYS = 0; 92 static final int VALUES = 1; 93 static final int ENTRIES = 2; 94 95 static final Iterator cEmptyHashIterator = new Iterator() { 96 public boolean hasNext() { 97 return false; 98 } 99 100 public Object next() { 101 throw new NoSuchElementException(); 102 } 103 104 public void remove() { 105 throw new IllegalStateException (); 106 } 107 }; 108 109 112 144 145 149 static String toString(Collection c) { 150 StringBuffer buf = new StringBuffer (); 151 Iterator it = c.iterator(); 152 buf.append("["); 153 for (int i = 0; it.hasNext(); i++) { 154 if (i > 0) { 155 buf.append(", "); 156 } 157 buf.append(String.valueOf(it.next())); 158 } 159 buf.append("]"); 160 return buf.toString(); 161 } 162 163 166 private transient Entry mTable[]; 167 168 171 private transient int mCount; 172 173 179 private int mThreshold; 180 181 186 private float mLoadFactor; 187 188 195 private transient int mModCount = 0; 196 197 199 private transient Set mKeySet = null; 200 private transient Set mEntrySet = null; 201 private transient Collection mValues = null; 202 203 212 public IdentityMap(int initialCapacity, float loadFactor) { 213 if (initialCapacity < 0) { 214 throw new IllegalArgumentException ("Illegal Initial Capacity: "+ 215 initialCapacity); 216 } 217 218 if (loadFactor <= 0 || Float.isNaN(loadFactor)) { 219 throw new IllegalArgumentException ("Illegal Load factor: "+ 220 loadFactor); 221 } 222 223 if (initialCapacity == 0) { 224 initialCapacity = 1; 225 } 226 227 mLoadFactor = loadFactor; 228 mTable = new Entry[initialCapacity]; 229 mThreshold = (int)(initialCapacity * loadFactor); 230 } 231 232 240 public IdentityMap(int initialCapacity) { 241 this(initialCapacity, 0.75f); 242 } 243 244 248 public IdentityMap() { 249 this(11, 0.75f); 250 } 251 252 258 public IdentityMap(Map t) { 259 this(Math.max(2 * t.size(), 11), 0.75f); 260 putAll(t); 261 } 262 263 269 public int size() { 270 return mCount; 271 } 272 273 278 public boolean isEmpty() { 279 return mCount == 0; 280 } 281 282 290 public boolean containsValue(Object value) { 291 Entry tab[] = mTable; 292 293 if (value == null) { 294 for (int i = tab.length ; i-- > 0 ;) { 295 for (Entry e = tab[i], prev = null; e != null; e = e.mNext) { 296 if (e.getKey() == null) { 297 mModCount++; 299 if (prev != null) { 300 prev.mNext = e.mNext; 301 } 302 else { 303 tab[i] = e.mNext; 304 } 305 mCount--; 306 } 307 else if (e.mValue == null) { 308 return true; 309 } 310 else { 311 prev = e; 312 } 313 } 314 } 315 } 316 else { 317 for (int i = tab.length ; i-- > 0 ;) { 318 for (Entry e = tab[i], prev = null; e != null; e = e.mNext) { 319 if (e.getKey() == null) { 320 mModCount++; 322 if (prev != null) { 323 prev.mNext = e.mNext; 324 } 325 else { 326 tab[i] = e.mNext; 327 } 328 mCount--; 329 } 330 else if (value.equals(e.mValue)) { 331 return true; 332 } 333 else { 334 prev = e; 335 } 336 } 337 } 338 } 339 340 return false; 341 } 342 343 351 public boolean containsKey(Object key) { 352 if (key == null) { 353 return false; 354 } 355 356 Entry tab[] = mTable; 357 int hash = System.identityHashCode(key); 358 int index = (hash & 0x7FFFFFFF) % tab.length; 359 360 for (Entry e = tab[index], prev = null; e != null; e = e.mNext) { 361 Object entryKey = e.getKey(); 362 363 if (entryKey == null) { 364 mModCount++; 366 if (prev != null) { 367 prev.mNext = e.mNext; 368 } 369 else { 370 tab[index] = e.mNext; 371 } 372 mCount--; 373 } 374 else if (e.mHash == hash && key == entryKey) { 375 return true; 376 } 377 else { 378 prev = e; 379 } 380 } 381 382 return false; 383 } 384 385 396 public Object get(Object key) { 397 if (key == null) { 398 return null; 399 } 400 401 Entry tab[] = mTable; 402 int hash = System.identityHashCode(key); 403 int index = (hash & 0x7FFFFFFF) % tab.length; 404 405 for (Entry e = tab[index], prev = null; e != null; e = e.mNext) { 406 Object entryKey = e.getKey(); 407 408 if (entryKey == null) { 409 mModCount++; 411 if (prev != null) { 412 prev.mNext = e.mNext; 413 } 414 else { 415 tab[index] = e.mNext; 416 } 417 mCount--; 418 } 419 else if (e.mHash == hash && key == entryKey) { 420 return e.mValue; 421 } 422 else { 423 prev = e; 424 } 425 } 426 427 return null; 428 } 429 430 434 private void cleanup() { 435 Entry tab[] = mTable; 436 437 for (int i = tab.length ; i-- > 0 ;) { 438 for (Entry e = tab[i], prev = null; e != null; e = e.mNext) { 439 if (e.getKey() == null) { 440 mModCount++; 442 if (prev != null) { 443 prev.mNext = e.mNext; 444 } 445 else { 446 tab[i] = e.mNext; 447 } 448 mCount--; 449 } 450 else { 451 prev = e; 452 } 453 } 454 } 455 } 456 457 462 private void rehash() { 463 int oldCapacity = mTable.length; 464 Entry oldMap[] = mTable; 465 466 int newCapacity = oldCapacity * 2 + 1; 467 Entry newMap[] = new Entry[newCapacity]; 468 469 mModCount++; 470 mThreshold = (int)(newCapacity * mLoadFactor); 471 mTable = newMap; 472 473 for (int i = oldCapacity ; i-- > 0 ;) { 474 for (Entry old = oldMap[i] ; old != null ; ) { 475 Entry e = old; 476 old = old.mNext; 477 478 if (e.getKey() == null) { 480 mCount--; 481 } 482 else { 483 int index = (e.mHash & 0x7FFFFFFF) % newCapacity; 484 e.mNext = newMap[index]; 485 newMap[index] = e; 486 } 487 } 488 } 489 } 490 491 503 public Object put(Object key, Object value) { 504 if (key == null) { 505 throw new NullPointerException ("Null key is not permitted"); 506 } 507 508 Entry tab[] = mTable; 510 int hash = System.identityHashCode(key); 511 int index = (hash & 0x7FFFFFFF) % tab.length; 512 513 for (Entry e = tab[index], prev = null; e != null; e = e.mNext) { 514 Object entryKey = e.getKey(); 515 516 if (entryKey == null) { 517 mModCount++; 519 if (prev != null) { 520 prev.mNext = e.mNext; 521 } 522 else { 523 tab[index] = e.mNext; 524 } 525 mCount--; 526 } 527 else if (e.mHash == hash && key == entryKey) { 528 Object old = e.mValue; 529 e.mValue = value; 530 return old; 531 } 532 else { 533 prev = e; 534 } 535 } 536 537 mModCount++; 538 539 if (mCount >= mThreshold) { 540 cleanup(); 542 } 543 544 if (mCount >= mThreshold) { 545 rehash(); 547 tab = mTable; 548 index = (hash & 0x7FFFFFFF) % tab.length; 549 } 550 551 Entry e = new Entry(hash, key, value, tab[index]); 553 tab[index] = e; 554 mCount++; 555 return null; 556 } 557 558 567 public Object remove(Object key) { 568 Entry tab[] = mTable; 569 int hash = System.identityHashCode(key); 570 int index = (hash & 0x7FFFFFFF) % tab.length; 571 572 for (Entry e = tab[index], prev = null; e != null; e = e.mNext) { 573 Object entryKey = e.getKey(); 574 575 if (entryKey == null) { 576 mModCount++; 578 if (prev != null) { 579 prev.mNext = e.mNext; 580 } 581 else { 582 tab[index] = e.mNext; 583 } 584 mCount--; 585 } 586 else if (e.mHash == hash && key == entryKey) { 587 mModCount++; 588 if (prev != null) { 589 prev.mNext = e.mNext; 590 } 591 else { 592 tab[index] = e.mNext; 593 } 594 mCount--; 595 596 Object oldValue = e.mValue; 597 e.mValue = null; 598 return oldValue; 599 } 600 else { 601 prev = e; 602 } 603 } 604 605 return null; 606 } 607 608 616 public void putAll(Map t) { 617 Iterator i = t.entrySet().iterator(); 618 while (i.hasNext()) { 619 Map.Entry e = (Map.Entry) i.next(); 620 put(e.getKey(), e.getValue()); 621 } 622 } 623 624 627 public void clear() { 628 Entry tab[] = mTable; 629 mModCount++; 630 for (int index = tab.length; --index >= 0; ) { 631 tab[index] = null; 632 } 633 mCount = 0; 634 } 635 636 642 public Object clone() { 643 try { 644 IdentityMap t = (IdentityMap)super.clone(); 645 t.mTable = new Entry[mTable.length]; 646 for (int i = mTable.length ; i-- > 0 ; ) { 647 t.mTable[i] = (mTable[i] != null) 648 ? (Entry)mTable[i].clone() : null; 649 } 650 t.mKeySet = null; 651 t.mEntrySet = null; 652 t.mValues = null; 653 t.mModCount = 0; 654 return t; 655 } 656 catch (CloneNotSupportedException e) { 657 throw new InternalError (); 659 } 660 } 661 662 673 public Set keySet() { 674 if (mKeySet == null) { 675 mKeySet = new AbstractSet() { 676 public Iterator iterator() { 677 return getHashIterator(KEYS); 678 } 679 public int size() { 680 return mCount; 681 } 682 public boolean contains(Object o) { 683 return containsKey(o); 684 } 685 public boolean remove(Object o) { 686 return o == null ? false : IdentityMap.this.remove(o) == o; 687 } 688 public void clear() { 689 IdentityMap.this.clear(); 690 } 691 public String toString() { 692 return IdentityMap.this.toString(this); 693 } 694 }; 695 } 696 return mKeySet; 697 } 698 699 710 public Collection values() { 711 if (mValues==null) { 712 mValues = new AbstractCollection() { 713 public Iterator iterator() { 714 return getHashIterator(VALUES); 715 } 716 public int size() { 717 return mCount; 718 } 719 public boolean contains(Object o) { 720 return containsValue(o); 721 } 722 public void clear() { 723 IdentityMap.this.clear(); 724 } 725 public String toString() { 726 return IdentityMap.this.toString(this); 727 } 728 }; 729 } 730 return mValues; 731 } 732 733 746 public Set entrySet() { 747 if (mEntrySet==null) { 748 mEntrySet = new AbstractSet() { 749 public Iterator iterator() { 750 return getHashIterator(ENTRIES); 751 } 752 753 public boolean contains(Object o) { 754 if (!(o instanceof Map.Entry)) { 755 return false; 756 } 757 Map.Entry entry = (Map.Entry)o; 758 Object key = entry.getKey(); 759 760 Entry tab[] = mTable; 761 int hash = System.identityHashCode(key); 762 int index = (hash & 0x7FFFFFFF) % tab.length; 763 764 for (Entry e = tab[index], prev = null; e != null; e = e.mNext) { 765 Object entryKey = e.getKey(); 766 767 if (entryKey == null) { 768 mModCount++; 770 if (prev != null) { 771 prev.mNext = e.mNext; 772 } 773 else { 774 tab[index] = e.mNext; 775 } 776 mCount--; 777 } 778 else if (e.mHash == hash && e.identityEquals(entry)) { 779 return true; 780 } 781 else { 782 prev = e; 783 } 784 } 785 786 return false; 787 } 788 789 public boolean remove(Object o) { 790 if (!(o instanceof Map.Entry)) { 791 return false; 792 } 793 Map.Entry entry = (Map.Entry)o; 794 Object key = entry.getKey(); 795 Entry tab[] = mTable; 796 int hash = System.identityHashCode(key); 797 int index = (hash & 0x7FFFFFFF) % tab.length; 798 799 for (Entry e = tab[index], prev = null; e != null; e = e.mNext) { 800 Object entryKey = e.getKey(); 801 802 if (entryKey == null) { 803 mModCount++; 805 if (prev != null) { 806 prev.mNext = e.mNext; 807 } 808 else { 809 tab[index] = e.mNext; 810 } 811 mCount--; 812 } 813 else if (e.mHash == hash && e.identityEquals(entry)) { 814 mModCount++; 815 if (prev != null) { 816 prev.mNext = e.mNext; 817 } 818 else { 819 tab[index] = e.mNext; 820 } 821 mCount--; 822 823 e.mValue = null; 824 return true; 825 } 826 else { 827 prev = e; 828 } 829 } 830 return false; 831 } 832 833 public int size() { 834 return mCount; 835 } 836 837 public void clear() { 838 IdentityMap.this.clear(); 839 } 840 841 public String toString() { 842 return IdentityMap.this.toString(this); 843 } 844 }; 845 } 846 847 return mEntrySet; 848 } 849 850 public String toString() { 851 StringBuffer buf = new StringBuffer (); 852 Iterator it = entrySet().iterator(); 853 854 buf.append("{"); 855 for (int i = 0; it.hasNext(); i++) { 856 if (i > 0) { 857 buf.append(", "); 858 } 859 Map.Entry e = (Map.Entry)it.next(); 860 buf.append(e.getKey() + "=" + e.getValue()); 861 } 862 buf.append("}"); 863 return buf.toString(); 864 } 865 866 private Iterator getHashIterator(int type) { 867 if (mCount == 0) { 868 return cEmptyHashIterator; 869 } 870 else { 871 return new HashIterator(type); 872 } 873 } 874 875 878 private static class Entry extends WeakReference implements Map.Entry { 879 int mHash; 880 Object mValue; 881 Entry mNext; 882 883 Entry(int hash, Object key, Object value, Entry next) { 884 super(key); 885 mHash = hash; 886 mValue = value; 887 mNext = next; 888 } 889 890 protected Object clone() { 891 return new Entry(mHash, getKey(), mValue, 892 (mNext == null ? null : (Entry)mNext.clone())); 893 } 894 895 897 public Object getKey() { 898 return Entry.this.get(); 899 } 900 901 public Object getValue() { 902 return mValue; 903 } 904 905 public Object setValue(Object value) { 906 Object oldValue = mValue; 907 mValue = value; 908 return oldValue; 909 } 910 911 public boolean equals(Object o) { 912 if (!(o instanceof Map.Entry)) { 913 return false; 914 } 915 Map.Entry e = (Map.Entry)o; 916 917 Object key = getKey(); 918 919 return (key==null ? e.getKey()==null : key.equals(e.getKey())) && 920 (mValue==null ? e.getValue()==null : mValue.equals(e.getValue())); 921 } 922 923 public boolean identityEquals(Map.Entry e) { 924 return (getKey() == e.getKey()) && 925 (mValue==null ? e.getValue()==null : mValue.equals(e.getValue())); 926 } 927 928 public int hashCode() { 929 return mHash ^ (mValue==null ? 0 : mValue.hashCode()); 930 } 931 932 public String toString() { 933 return getKey() + "=" + mValue; 934 } 935 } 936 937 private class HashIterator implements Iterator { 938 private Entry[] mTable = IdentityMap.this.mTable; 939 private int mIndex = mTable.length; 940 private Entry mEntry; 941 private Object mEntryKey; 945 private Entry mLastReturned; 946 private int mType; 947 948 953 private int expectedModCount = mModCount; 954 955 HashIterator(int type) { 956 mType = type; 957 } 958 959 public boolean hasNext() { 960 while (mEntry == null || 961 (mEntryKey = mEntry.getKey()) == null) { 962 if (mEntry != null) { 963 remove(mEntry); 965 mEntry = mEntry.mNext; 966 } 967 else { 968 if (mIndex <= 0) { 969 return false; 970 } 971 else { 972 mEntry = mTable[--mIndex]; 973 } 974 } 975 } 976 977 return true; 978 } 979 980 public Object next() { 981 if (mModCount != expectedModCount) { 982 throw new ConcurrentModificationException(); 983 } 984 985 if (!hasNext()) { 986 throw new NoSuchElementException(); 987 } 988 989 mLastReturned = mEntry; 990 mEntry = mEntry.mNext; 991 992 return mType == KEYS ? mLastReturned.getKey() : 993 (mType == VALUES ? mLastReturned.getValue() : mLastReturned); 994 } 995 996 public void remove() { 997 if (mLastReturned == null) { 998 throw new IllegalStateException (); 999 } 1000 if (mModCount != expectedModCount) { 1001 throw new ConcurrentModificationException(); 1002 } 1003 remove(mLastReturned); 1004 mLastReturned = null; 1005 } 1006 1007 private void remove(Entry toRemove) { 1008 Entry[] tab = mTable; 1009 int index = (toRemove.mHash & 0x7FFFFFFF) % tab.length; 1010 1011 for (Entry e = tab[index], prev = null; e != null; e = e.mNext) { 1012 if (e == toRemove) { 1013 mModCount++; 1014 expectedModCount++; 1015 if (prev == null) { 1016 tab[index] = e.mNext; 1017 } 1018 else { 1019 prev.mNext = e.mNext; 1020 } 1021 mCount--; 1022 return; 1023 } 1024 else { 1025 prev = e; 1026 } 1027 } 1028 throw new ConcurrentModificationException(); 1029 } 1030 } 1031} 1032
| Popular Tags
|