1 package org.codehaus.aspectwerkz.util; 2 3 63 64 import java.io.Externalizable ; 65 import java.io.IOException ; 66 import java.io.ObjectInput ; 67 import java.io.ObjectOutput ; 68 import java.util.AbstractCollection ; 69 import java.util.AbstractSet ; 70 import java.util.ArrayList ; 71 import java.util.Collection ; 72 import java.util.Collections ; 73 import java.util.ConcurrentModificationException ; 74 import java.util.HashMap ; 75 import java.util.Iterator ; 76 import java.util.List ; 77 import java.util.Map ; 78 import java.util.NoSuchElementException ; 79 import java.util.Set ; 80 81 97 public class SequencedHashMap implements Map , Cloneable , Externalizable { 98 private static final int KEY = 0; 100 101 private static final int VALUE = 1; 102 103 private static final int ENTRY = 2; 104 105 private static final int REMOVED_MASK = 0x80000000; 106 107 private static final long serialVersionUID = 3380552487888102930L; 110 111 114 private Entry sentinel; 115 116 119 private HashMap entries; 120 121 126 private transient long modCount = 0; 127 128 131 public SequencedHashMap() { 132 sentinel = createSentinel(); 133 entries = new HashMap (); 134 } 135 136 142 public SequencedHashMap(int initialSize) { 143 sentinel = createSentinel(); 144 entries = new HashMap (initialSize); 145 } 146 147 154 public SequencedHashMap(int initialSize, float loadFactor) { 155 sentinel = createSentinel(); 156 entries = new HashMap (initialSize, loadFactor); 157 } 158 159 163 public SequencedHashMap(Map m) { 164 this(); 165 putAll(m); 166 } 167 168 172 private static final Entry createSentinel() { 173 Entry s = new Entry(null, null); 174 s.prev = s; 175 s.next = s; 176 return s; 177 } 178 179 182 private void removeEntry(Entry entry) { 183 entry.next.prev = entry.prev; 184 entry.prev.next = entry.next; 185 } 186 187 190 private void insertEntry(Entry entry) { 191 entry.next = sentinel; 192 entry.prev = sentinel.prev; 193 sentinel.prev.next = entry; 194 sentinel.prev = entry; 195 } 196 197 199 202 public int size() { 203 return entries.size(); 205 } 206 207 210 public boolean isEmpty() { 211 return sentinel.next == sentinel; 214 } 215 216 219 public boolean containsKey(Object key) { 220 return entries.containsKey(key); 222 } 223 224 227 public boolean containsValue(Object value) { 228 if (value == null) { 236 for (Entry pos = sentinel.next; pos != sentinel; pos = pos.next) { 237 if (pos.getValue() == null) { 238 return true; 239 } 240 } 241 } else { 242 for (Entry pos = sentinel.next; pos != sentinel; pos = pos.next) { 243 if (value.equals(pos.getValue())) { 244 return true; 245 } 246 } 247 } 248 return false; 249 } 250 251 254 public Object get(Object o) { 255 Entry entry = (Entry) entries.get(o); 257 if (entry == null) { 258 return null; 259 } 260 return entry.getValue(); 261 } 262 263 270 public Map.Entry getFirst() { 271 return (isEmpty()) ? null : sentinel.next; 275 } 276 277 284 public Object getFirstKey() { 285 return sentinel.next.getKey(); 292 } 293 294 301 public Object getFirstValue() { 302 return sentinel.next.getValue(); 309 } 310 311 328 public Map.Entry getLast() { 329 return (isEmpty()) ? null : sentinel.prev; 333 } 334 335 342 public Object getLastKey() { 343 return sentinel.prev.getKey(); 350 } 351 352 359 public Object getLastValue() { 360 return sentinel.prev.getValue(); 367 } 368 369 372 public Object put(Object key, Object value) { 373 modCount++; 374 Object oldValue = null; 375 376 Entry e = (Entry) entries.get(key); 378 379 if (e != null) { 381 removeEntry(e); 383 384 oldValue = e.setValue(value); 386 387 } else { 393 e = new Entry(key, value); 395 entries.put(key, e); 396 } 397 398 insertEntry(e); 401 return oldValue; 402 } 403 404 407 public Object remove(Object key) { 408 Entry e = removeImpl(key); 409 return (e == null) ? null : e.getValue(); 410 } 411 412 416 private Entry removeImpl(Object key) { 417 Entry e = (Entry) entries.remove(key); 418 if (e == null) { 419 return null; 420 } 421 modCount++; 422 removeEntry(e); 423 return e; 424 } 425 426 434 public void putAll(Map t) { 435 Iterator iter = t.entrySet().iterator(); 436 while (iter.hasNext()) { 437 Map.Entry entry = (Map.Entry ) iter.next(); 438 put(entry.getKey(), entry.getValue()); 439 } 440 } 441 442 445 public void clear() { 446 modCount++; 447 448 entries.clear(); 450 451 sentinel.next = sentinel; 453 sentinel.prev = sentinel; 454 } 455 456 459 public boolean equals(Object obj) { 460 if (obj == null) { 461 return false; 462 } 463 if (obj == this) { 464 return true; 465 } 466 if (!(obj instanceof Map )) { 467 return false; 468 } 469 return entrySet().equals(((Map ) obj).entrySet()); 470 } 471 472 475 public int hashCode() { 476 return entrySet().hashCode(); 477 } 478 479 485 public String toString() { 486 StringBuffer buf = new StringBuffer (); 487 buf.append('['); 488 for (Entry pos = sentinel.next; pos != sentinel; pos = pos.next) { 489 buf.append(pos.getKey()); 490 buf.append('='); 491 buf.append(pos.getValue()); 492 if (pos.next != sentinel) { 493 buf.append(','); 494 } 495 } 496 buf.append(']'); 497 return buf.toString(); 498 } 499 500 503 public Set keySet() { 504 return new AbstractSet () { 505 public Iterator iterator() { 507 return new OrderedIterator(KEY); 508 } 509 510 public boolean remove(Object o) { 511 Entry e = SequencedHashMap.this.removeImpl(o); 512 return (e != null); 513 } 514 515 public void clear() { 517 SequencedHashMap.this.clear(); 518 } 519 520 public int size() { 521 return SequencedHashMap.this.size(); 522 } 523 524 public boolean isEmpty() { 525 return SequencedHashMap.this.isEmpty(); 526 } 527 528 public boolean contains(Object o) { 529 return SequencedHashMap.this.containsKey(o); 530 } 531 }; 532 } 533 534 537 public Collection values() { 538 return new AbstractCollection () { 539 public Iterator iterator() { 541 return new OrderedIterator(VALUE); 542 } 543 544 public boolean remove(Object value) { 545 if (value == null) { 549 for (Entry pos = sentinel.next; pos != sentinel; pos = pos.next) { 550 if (pos.getValue() == null) { 551 SequencedHashMap.this.removeImpl(pos.getKey()); 552 return true; 553 } 554 } 555 } else { 556 for (Entry pos = sentinel.next; pos != sentinel; pos = pos.next) { 557 if (value.equals(pos.getValue())) { 558 SequencedHashMap.this.removeImpl(pos.getKey()); 559 return true; 560 } 561 } 562 } 563 return false; 564 } 565 566 public void clear() { 568 SequencedHashMap.this.clear(); 569 } 570 571 public int size() { 572 return SequencedHashMap.this.size(); 573 } 574 575 public boolean isEmpty() { 576 return SequencedHashMap.this.isEmpty(); 577 } 578 579 public boolean contains(Object o) { 580 return SequencedHashMap.this.containsValue(o); 581 } 582 }; 583 } 584 585 588 public Set entrySet() { 589 return new AbstractSet () { 590 private Entry findEntry(Object o) { 592 if (o == null) { 593 return null; 594 } 595 if (!(o instanceof Map.Entry )) { 596 return null; 597 } 598 Map.Entry e = (Map.Entry ) o; 599 Entry entry = (Entry) entries.get(e.getKey()); 600 if ((entry != null) && entry.equals(e)) { 601 return entry; 602 } else { 603 return null; 604 } 605 } 606 607 public Iterator iterator() { 609 return new OrderedIterator(ENTRY); 610 } 611 612 public boolean remove(Object o) { 613 Entry e = findEntry(o); 614 if (e == null) { 615 return false; 616 } 617 return SequencedHashMap.this.removeImpl(e.getKey()) != null; 618 } 619 620 public void clear() { 622 SequencedHashMap.this.clear(); 623 } 624 625 public int size() { 626 return SequencedHashMap.this.size(); 627 } 628 629 public boolean isEmpty() { 630 return SequencedHashMap.this.isEmpty(); 631 } 632 633 public boolean contains(Object o) { 634 return findEntry(o) != null; 635 } 636 }; 637 } 638 639 642 649 public Object clone() throws CloneNotSupportedException { 650 SequencedHashMap map = (SequencedHashMap) super.clone(); 655 656 map.sentinel = createSentinel(); 658 659 map.entries = new HashMap (); 662 663 map.putAll(this); 665 666 return map; 674 } 675 676 682 private Map.Entry getEntry(int index) { 683 Entry pos = sentinel; 684 if (index < 0) { 685 throw new ArrayIndexOutOfBoundsException (index + " < 0"); 686 } 687 688 int i = -1; 690 while ((i < (index - 1)) && (pos.next != sentinel)) { 691 i++; 692 pos = pos.next; 693 } 694 695 if (pos.next == sentinel) { 698 throw new ArrayIndexOutOfBoundsException (index + " >= " + (i + 1)); 699 } 700 return pos.next; 701 } 702 703 709 public Object get(int index) { 710 return getEntry(index).getKey(); 711 } 712 713 719 public Object getValue(int index) { 720 return getEntry(index).getValue(); 721 } 722 723 726 public int indexOf(Object key) { 727 Entry e = (Entry) entries.get(key); 728 int pos = 0; 729 while (e.prev != sentinel) { 730 pos++; 731 e = e.prev; 732 } 733 return pos; 734 } 735 736 739 public Iterator iterator() { 740 return keySet().iterator(); 741 } 742 743 746 public int lastIndexOf(Object key) { 747 return indexOf(key); 749 } 750 751 763 public List sequence() { 764 List l = new ArrayList (size()); 765 Iterator iter = keySet().iterator(); 766 while (iter.hasNext()) { 767 l.add(iter.next()); 768 } 769 return Collections.unmodifiableList(l); 770 } 771 772 780 public Object remove(int index) { 781 return remove(get(index)); 782 } 783 784 786 793 public void readExternal(ObjectInput in) throws IOException , ClassNotFoundException { 794 int size = in.readInt(); 795 for (int i = 0; i < size; i++) { 796 Object key = in.readObject(); 797 Object value = in.readObject(); 798 put(key, value); 799 } 800 } 801 802 808 public void writeExternal(ObjectOutput out) throws IOException { 809 out.writeInt(size()); 810 for (Entry pos = sentinel.next; pos != sentinel; pos = pos.next) { 811 out.writeObject(pos.getKey()); 812 out.writeObject(pos.getValue()); 813 } 814 } 815 816 819 private static class Entry implements Map.Entry { 820 private final Object key; 830 831 private Object value; 832 833 Entry next = null; 836 837 Entry prev = null; 838 839 public Entry(Object key, Object value) { 840 this.key = key; 841 this.value = value; 842 } 843 844 public Object getKey() { 846 return this.key; 847 } 848 849 public Object getValue() { 851 return this.value; 852 } 853 854 public Object setValue(Object value) { 856 Object oldValue = this.value; 857 this.value = value; 858 return oldValue; 859 } 860 861 public int hashCode() { 862 return (((getKey() == null) ? 0 : getKey().hashCode()) ^ 864 ((getValue() == null) ? 0 : getValue().hashCode())); 865 } 866 867 public boolean equals(Object obj) { 868 if (obj == null) { 869 return false; 870 } 871 if (obj == this) { 872 return true; 873 } 874 if (!(obj instanceof Map.Entry )) { 875 return false; 876 } 877 Map.Entry other = (Map.Entry ) obj; 878 879 return (((getKey() == null) ? (other.getKey() == null) : getKey().equals(other.getKey())) && ((getValue() == 881 null) 882 ? 883 (other.getValue() == 884 null) 885 : 886 getValue() 887 .equals(other.getValue()))); 888 } 889 890 public String toString() { 891 return "[" + getKey() + '=' + getValue() + ']'; 892 } 893 } 894 895 private class OrderedIterator implements Iterator { 896 903 private int returnType; 904 905 909 private Entry pos = sentinel; 910 911 915 private transient long expectedModCount = modCount; 916 917 922 public OrderedIterator(int returnType) { 923 this.returnType = returnType | REMOVED_MASK; 933 } 934 935 941 public boolean hasNext() { 942 return pos.next != sentinel; 943 } 944 945 953 public Object next() { 954 if (modCount != expectedModCount) { 955 throw new ConcurrentModificationException (); 956 } 957 if (pos.next == sentinel) { 958 throw new NoSuchElementException (); 959 } 960 961 returnType = returnType & ~REMOVED_MASK; 963 pos = pos.next; 964 switch (returnType) { 965 case KEY: 966 return pos.getKey(); 967 case VALUE: 968 return pos.getValue(); 969 case ENTRY: 970 return pos; 971 default: 972 973 throw new Error ("bad iterator type: " + returnType); 975 } 976 } 977 978 986 public void remove() { 987 if ((returnType & REMOVED_MASK) != 0) { 988 throw new IllegalStateException ("remove() must follow next()"); 989 } 990 if (modCount != expectedModCount) { 991 throw new ConcurrentModificationException (); 992 } 993 SequencedHashMap.this.removeImpl(pos.getKey()); 994 995 expectedModCount++; 997 998 returnType = returnType | REMOVED_MASK; 1000 } 1001 } 1002} | Popular Tags |