1 52 53 package freemarker.ext.util; 54 55 import java.util.AbstractCollection ; 56 import java.util.AbstractMap ; 57 import java.util.AbstractSet ; 58 import java.util.Collection ; 59 import java.util.ConcurrentModificationException ; 60 import java.util.Iterator ; 61 import java.util.Map ; 62 import java.util.NoSuchElementException ; 63 import java.util.Set ; 64 65 72 public class IdentityHashMap 73 extends AbstractMap 74 implements Map , Cloneable , java.io.Serializable 75 { 76 77 public static final long serialVersionUID = 362498820763181265L; 78 81 private transient Entry table[]; 82 83 86 private transient int count; 87 88 94 private int threshold; 95 96 101 private float loadFactor; 102 103 110 private transient int modCount = 0; 111 112 121 public IdentityHashMap(int initialCapacity, float loadFactor) 122 { 123 if (initialCapacity < 0) 124 throw new IllegalArgumentException ( 125 "Illegal Initial Capacity: " + initialCapacity); 126 if (loadFactor <= 0 || Float.isNaN(loadFactor)) 127 throw new IllegalArgumentException ( 128 "Illegal Load factor: " + loadFactor); 129 if (initialCapacity == 0) 130 initialCapacity = 1; 131 this.loadFactor = loadFactor; 132 table = new Entry[initialCapacity]; 133 threshold = (int) (initialCapacity * loadFactor); 134 } 135 136 144 public IdentityHashMap(int initialCapacity) 145 { 146 this(initialCapacity, 0.75f); 147 } 148 149 153 public IdentityHashMap() 154 { 155 this(11, 0.75f); 156 } 157 158 166 public IdentityHashMap(Map t) 167 { 168 this(Math.max(2 * t.size(), 11), 0.75f); 169 putAll(t); 170 } 171 172 177 public int size() 178 { 179 return count; 180 } 181 182 187 public boolean isEmpty() 188 { 189 return count == 0; 190 } 191 192 200 public boolean containsValue(Object value) 201 { 202 Entry tab[] = table; 203 204 if (value == null) 205 { 206 for (int i = tab.length; i-- > 0;) 207 for (Entry e = tab[i]; e != null; e = e.next) 208 if (e.value == null) 209 return true; 210 } 211 else 212 { 213 for (int i = tab.length; i-- > 0;) 214 for (Entry e = tab[i]; e != null; e = e.next) 215 if (value.equals(e.value)) 216 return true; 217 } 218 219 return false; 220 } 221 222 230 public boolean containsKey(Object key) 231 { 232 Entry tab[] = table; 233 if (key != null) 234 { 235 int hash = System.identityHashCode(key); 236 int index = (hash & 0x7FFFFFFF) % tab.length; 237 for (Entry e = tab[index]; e != null; e = e.next) 238 if (e.hash == hash && key == e.key) 239 return true; 240 } 241 else 242 { 243 for (Entry e = tab[0]; e != null; e = e.next) 244 if (e.key == null) 245 return true; 246 } 247 248 return false; 249 } 250 251 262 public Object get(Object key) 263 { 264 Entry tab[] = table; 265 266 if (key != null) 267 { 268 int hash = System.identityHashCode(key); 269 int index = (hash & 0x7FFFFFFF) % tab.length; 270 for (Entry e = tab[index]; e != null; e = e.next) 271 if ((e.hash == hash) && key == e.key) 272 return e.value; 273 } 274 else 275 { 276 for (Entry e = tab[0]; e != null; e = e.next) 277 if (e.key == null) 278 return e.value; 279 } 280 281 return null; 282 } 283 284 289 private void rehash() 290 { 291 int oldCapacity = table.length; 292 Entry oldMap[] = table; 293 294 int newCapacity = oldCapacity * 2 + 1; 295 Entry newMap[] = new Entry[newCapacity]; 296 297 modCount++; 298 threshold = (int) (newCapacity * loadFactor); 299 table = newMap; 300 301 for (int i = oldCapacity; i-- > 0;) 302 { 303 for (Entry old = oldMap[i]; old != null;) 304 { 305 Entry e = old; 306 old = old.next; 307 308 int index = (e.hash & 0x7FFFFFFF) % newCapacity; 309 e.next = newMap[index]; 310 newMap[index] = e; 311 } 312 } 313 } 314 315 327 public Object put(Object key, Object value) 328 { 329 Entry tab[] = table; 331 int hash = 0; 332 int index = 0; 333 334 if (key != null) 335 { 336 hash = System.identityHashCode(key); 337 index = (hash & 0x7FFFFFFF) % tab.length; 338 for (Entry e = tab[index]; e != null; e = e.next) 339 { 340 if ((e.hash == hash) && key == e.key) 341 { 342 Object old = e.value; 343 e.value = value; 344 return old; 345 } 346 } 347 } 348 else 349 { 350 for (Entry e = tab[0]; e != null; e = e.next) 351 { 352 if (e.key == null) 353 { 354 Object old = e.value; 355 e.value = value; 356 return old; 357 } 358 } 359 } 360 361 modCount++; 362 if (count >= threshold) 363 { 364 rehash(); 366 367 tab = table; 368 index = (hash & 0x7FFFFFFF) % tab.length; 369 } 370 371 Entry e = new Entry(hash, key, value, tab[index]); 373 tab[index] = e; 374 count++; 375 return null; 376 } 377 378 387 public Object remove(Object key) 388 { 389 Entry tab[] = table; 390 391 if (key != null) 392 { 393 int hash = System.identityHashCode(key); 394 int index = (hash & 0x7FFFFFFF) % tab.length; 395 396 for (Entry e = tab[index], prev = null; 397 e != null; 398 prev = e, e = e.next) 399 { 400 if ((e.hash == hash) && key == e.key) 401 { 402 modCount++; 403 if (prev != null) 404 prev.next = e.next; 405 else 406 tab[index] = e.next; 407 408 count--; 409 Object oldValue = e.value; 410 e.value = null; 411 return oldValue; 412 } 413 } 414 } 415 else 416 { 417 for (Entry e = tab[0], prev = null; 418 e != null; 419 prev = e, e = e.next) 420 { 421 if (e.key == null) 422 { 423 modCount++; 424 if (prev != null) 425 prev.next = e.next; 426 else 427 tab[0] = e.next; 428 429 count--; 430 Object oldValue = e.value; 431 e.value = null; 432 return oldValue; 433 } 434 } 435 } 436 437 return null; 438 } 439 440 448 public void putAll(Map t) 449 { 450 Iterator i = t.entrySet().iterator(); 451 while (i.hasNext()) 452 { 453 Map.Entry e = (Map.Entry ) i.next(); 454 put(e.getKey(), e.getValue()); 455 } 456 } 457 458 461 public void clear() 462 { 463 Entry tab[] = table; 464 modCount++; 465 for (int index = tab.length; --index >= 0;) 466 tab[index] = null; 467 count = 0; 468 } 469 470 476 public Object clone() 477 { 478 try 479 { 480 IdentityHashMap t = (IdentityHashMap) super.clone(); 481 t.table = new Entry[table.length]; 482 for (int i = table.length; i-- > 0;) 483 { 484 t.table[i] = 485 (table[i] != null) ? (Entry) table[i].clone() : null; 486 } 487 t.keySet = null; 488 t.entrySet = null; 489 t.values = null; 490 t.modCount = 0; 491 return t; 492 } 493 catch (CloneNotSupportedException e) 494 { 495 throw new InternalError (); 497 } 498 } 499 500 502 private transient Set keySet = null; 503 private transient Set entrySet = null; 504 private transient Collection values = null; 505 506 517 public Set keySet() 518 { 519 if (keySet == null) 520 { 521 keySet = new AbstractSet () 522 { 523 public Iterator iterator() 524 { 525 return getHashIterator(KEYS); 526 } 527 public int size() 528 { 529 return count; 530 } 531 public boolean contains(Object o) 532 { 533 return containsKey(o); 534 } 535 public boolean remove(Object o) 536 { 537 int oldSize = count; 538 IdentityHashMap.this.remove(o); 539 return count != oldSize; 540 } 541 public void clear() 542 { 543 IdentityHashMap.this.clear(); 544 } 545 }; 546 } 547 return keySet; 548 } 549 550 561 public Collection values() 562 { 563 if (values == null) 564 { 565 values = new AbstractCollection () 566 { 567 public Iterator iterator() 568 { 569 return getHashIterator(VALUES); 570 } 571 public int size() 572 { 573 return count; 574 } 575 public boolean contains(Object o) 576 { 577 return containsValue(o); 578 } 579 public void clear() 580 { 581 IdentityHashMap.this.clear(); 582 } 583 }; 584 } 585 return values; 586 } 587 588 601 public Set entrySet() 602 { 603 if (entrySet == null) 604 { 605 entrySet = new AbstractSet () 606 { 607 public Iterator iterator() 608 { 609 return getHashIterator(ENTRIES); 610 } 611 612 public boolean contains(Object o) 613 { 614 if (!(o instanceof Map.Entry )) 615 return false; 616 Map.Entry entry = (Map.Entry ) o; 617 Object key = entry.getKey(); 618 Entry tab[] = table; 619 int hash = (key == null ? 0 : System.identityHashCode(key)); 620 int index = (hash & 0x7FFFFFFF) % tab.length; 621 622 for (Entry e = tab[index]; e != null; e = e.next) 623 if (e.hash == hash && e.equals(entry)) 624 return true; 625 return false; 626 } 627 628 public boolean remove(Object o) 629 { 630 if (!(o instanceof Map.Entry )) 631 return false; 632 Map.Entry entry = (Map.Entry ) o; 633 Object key = entry.getKey(); 634 Entry tab[] = table; 635 int hash = (key == null ? 0 : System.identityHashCode(key)); 636 int index = (hash & 0x7FFFFFFF) % tab.length; 637 638 for (Entry e = tab[index], prev = null; 639 e != null; 640 prev = e, e = e.next) 641 { 642 if (e.hash == hash && e.equals(entry)) 643 { 644 modCount++; 645 if (prev != null) 646 prev.next = e.next; 647 else 648 tab[index] = e.next; 649 650 count--; 651 e.value = null; 652 return true; 653 } 654 } 655 return false; 656 } 657 658 public int size() 659 { 660 return count; 661 } 662 663 public void clear() 664 { 665 IdentityHashMap.this.clear(); 666 } 667 }; 668 } 669 670 return entrySet; 671 } 672 673 private Iterator getHashIterator(int type) 674 { 675 if (count == 0) 676 { 677 return emptyHashIterator; 678 } 679 else 680 { 681 return new HashIterator(type); 682 } 683 } 684 685 688 private static class Entry implements Map.Entry 689 { 690 int hash; 691 Object key; 692 Object value; 693 Entry next; 694 695 Entry(int hash, Object key, Object value, Entry next) 696 { 697 this.hash = hash; 698 this.key = key; 699 this.value = value; 700 this.next = next; 701 } 702 703 protected Object clone() 704 { 705 return new Entry( 706 hash, 707 key, 708 value, 709 (next == null ? null : (Entry) next.clone())); 710 } 711 712 714 public Object getKey() 715 { 716 return key; 717 } 718 719 public Object getValue() 720 { 721 return value; 722 } 723 724 public Object setValue(Object value) 725 { 726 Object oldValue = this.value; 727 this.value = value; 728 return oldValue; 729 } 730 731 public boolean equals(Object o) 732 { 733 if (!(o instanceof Map.Entry )) 734 return false; 735 Map.Entry e = (Map.Entry ) o; 736 737 return (key == e.getKey()) 738 && (value == null 739 ? e.getValue() == null 740 : value.equals(e.getValue())); 741 } 742 743 public int hashCode() 744 { 745 return hash ^ (value == null ? 0 : value.hashCode()); 746 } 747 748 public String toString() 749 { 750 return key + "=" + value; 751 } 752 } 753 754 private static final int KEYS = 0; 756 private static final int VALUES = 1; 757 private static final int ENTRIES = 2; 758 759 private static EmptyHashIterator emptyHashIterator = 760 new EmptyHashIterator(); 761 762 private static class EmptyHashIterator implements Iterator 763 { 764 765 EmptyHashIterator() 766 { 767 768 } 769 770 public boolean hasNext() 771 { 772 return false; 773 } 774 775 public Object next() 776 { 777 throw new NoSuchElementException (); 778 } 779 780 public void remove() 781 { 782 throw new IllegalStateException (); 783 } 784 785 } 786 787 private class HashIterator implements Iterator 788 { 789 Entry[] table = IdentityHashMap.this.table; 790 int index = table.length; 791 Entry entry = null; 792 Entry lastReturned = null; 793 int type; 794 795 800 private int expectedModCount = modCount; 801 802 HashIterator(int type) 803 { 804 this.type = type; 805 } 806 807 public boolean hasNext() 808 { 809 Entry e = entry; 810 int i = index; 811 Entry t[] = table; 812 813 while (e == null && i > 0) 814 e = t[--i]; 815 entry = e; 816 index = i; 817 return e != null; 818 } 819 820 public Object next() 821 { 822 if (modCount != expectedModCount) 823 throw new ConcurrentModificationException (); 824 825 Entry et = entry; 826 int i = index; 827 Entry t[] = table; 828 829 830 while (et == null && i > 0) 831 et = t[--i]; 832 833 entry = et; 834 index = i; 835 if (et != null) 836 { 837 Entry e = lastReturned = entry; 838 entry = e.next; 839 return type == KEYS ? e.key : (type == VALUES ? e.value : e); 840 } 841 throw new NoSuchElementException (); 842 } 843 844 public void remove() 845 { 846 if (lastReturned == null) 847 throw new IllegalStateException (); 848 if (modCount != expectedModCount) 849 throw new ConcurrentModificationException (); 850 851 Entry[] tab = IdentityHashMap.this.table; 852 int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length; 853 854 for (Entry e = tab[index], prev = null; 855 e != null; 856 prev = e, e = e.next) 857 { 858 if (e == lastReturned) 859 { 860 modCount++; 861 expectedModCount++; 862 if (prev == null) 863 tab[index] = e.next; 864 else 865 prev.next = e.next; 866 count--; 867 lastReturned = null; 868 return; 869 } 870 } 871 throw new ConcurrentModificationException (); 872 } 873 } 874 875 886 private void writeObject(java.io.ObjectOutputStream s) 887 throws java.io.IOException 888 { 889 s.defaultWriteObject(); 891 892 s.writeInt(table.length); 894 895 s.writeInt(count); 897 898 for (int index = table.length - 1; index >= 0; index--) 900 { 901 Entry entry = table[index]; 902 903 while (entry != null) 904 { 905 s.writeObject(entry.key); 906 s.writeObject(entry.value); 907 entry = entry.next; 908 } 909 } 910 } 911 912 916 private void readObject(java.io.ObjectInputStream s) 917 throws java.io.IOException , ClassNotFoundException 918 { 919 s.defaultReadObject(); 921 922 int numBuckets = s.readInt(); 924 table = new Entry[numBuckets]; 925 926 int size = s.readInt(); 928 929 for (int i = 0; i < size; i++) 931 { 932 Object key = s.readObject(); 933 Object value = s.readObject(); 934 put(key, value); 935 } 936 } 937 938 int capacity() 939 { 940 return table.length; 941 } 942 943 float loadFactor() 944 { 945 return loadFactor; 946 } 947 } 948 | Popular Tags |