1 4 5 package com.tc.aspectwerkz.util; 6 7 import java.io.Externalizable ; 8 import java.io.IOException ; 9 import java.io.ObjectInput ; 10 import java.io.ObjectOutput ; 11 import java.util.AbstractCollection ; 12 import java.util.AbstractSet ; 13 import java.util.ArrayList ; 14 import java.util.Collection ; 15 import java.util.Collections ; 16 import java.util.ConcurrentModificationException ; 17 import java.util.HashMap ; 18 import java.util.Iterator ; 19 import java.util.List ; 20 import java.util.Map ; 21 import java.util.NoSuchElementException ; 22 import java.util.Set ; 23 24 40 public class SequencedHashMap implements Map , Cloneable , Externalizable { 41 private static final int KEY = 0; 43 44 private static final int VALUE = 1; 45 46 private static final int ENTRY = 2; 47 48 private static final int REMOVED_MASK = 0x80000000; 49 50 private static final long serialVersionUID = 3380552487888102930L; 53 54 57 private Entry sentinel; 58 59 62 private HashMap entries; 63 64 69 private transient long modCount = 0; 70 71 74 public SequencedHashMap() { 75 sentinel = createSentinel(); 76 entries = new HashMap (); 77 } 78 79 85 public SequencedHashMap(int initialSize) { 86 sentinel = createSentinel(); 87 entries = new HashMap (initialSize); 88 } 89 90 97 public SequencedHashMap(int initialSize, float loadFactor) { 98 sentinel = createSentinel(); 99 entries = new HashMap (initialSize, loadFactor); 100 } 101 102 106 public SequencedHashMap(Map m) { 107 this(); 108 putAll(m); 109 } 110 111 115 private static final Entry createSentinel() { 116 Entry s = new Entry(null, null); 117 s.prev = s; 118 s.next = s; 119 return s; 120 } 121 122 125 private void removeEntry(Entry entry) { 126 entry.next.prev = entry.prev; 127 entry.prev.next = entry.next; 128 } 129 130 133 private void insertEntry(Entry entry) { 134 entry.next = sentinel; 135 entry.prev = sentinel.prev; 136 sentinel.prev.next = entry; 137 sentinel.prev = entry; 138 } 139 140 142 145 public int size() { 146 return entries.size(); 148 } 149 150 153 public boolean isEmpty() { 154 return sentinel.next == sentinel; 157 } 158 159 162 public boolean containsKey(Object key) { 163 return entries.containsKey(key); 165 } 166 167 170 public boolean containsValue(Object value) { 171 if (value == null) { 179 for (Entry pos = sentinel.next; pos != sentinel; pos = pos.next) { 180 if (pos.getValue() == null) { 181 return true; 182 } 183 } 184 } else { 185 for (Entry pos = sentinel.next; pos != sentinel; pos = pos.next) { 186 if (value.equals(pos.getValue())) { 187 return true; 188 } 189 } 190 } 191 return false; 192 } 193 194 197 public Object get(Object o) { 198 Entry entry = (Entry) entries.get(o); 200 if (entry == null) { 201 return null; 202 } 203 return entry.getValue(); 204 } 205 206 213 public Map.Entry getFirst() { 214 return (isEmpty()) ? null : sentinel.next; 218 } 219 220 227 public Object getFirstKey() { 228 return sentinel.next.getKey(); 235 } 236 237 244 public Object getFirstValue() { 245 return sentinel.next.getValue(); 252 } 253 254 271 public Map.Entry getLast() { 272 return (isEmpty()) ? null : sentinel.prev; 276 } 277 278 285 public Object getLastKey() { 286 return sentinel.prev.getKey(); 293 } 294 295 302 public Object getLastValue() { 303 return sentinel.prev.getValue(); 310 } 311 312 315 public Object put(Object key, Object value) { 316 modCount++; 317 Object oldValue = null; 318 319 Entry e = (Entry) entries.get(key); 321 322 if (e != null) { 324 removeEntry(e); 326 327 oldValue = e.setValue(value); 329 330 } else { 336 e = new Entry(key, value); 338 entries.put(key, e); 339 } 340 341 insertEntry(e); 344 return oldValue; 345 } 346 347 350 public Object remove(Object key) { 351 Entry e = removeImpl(key); 352 return (e == null) ? null : e.getValue(); 353 } 354 355 359 private Entry removeImpl(Object key) { 360 Entry e = (Entry) entries.remove(key); 361 if (e == null) { 362 return null; 363 } 364 modCount++; 365 removeEntry(e); 366 return e; 367 } 368 369 377 public void putAll(Map t) { 378 Iterator iter = t.entrySet().iterator(); 379 while (iter.hasNext()) { 380 Map.Entry entry = (Map.Entry ) iter.next(); 381 put(entry.getKey(), entry.getValue()); 382 } 383 } 384 385 388 public void clear() { 389 modCount++; 390 391 entries.clear(); 393 394 sentinel.next = sentinel; 396 sentinel.prev = sentinel; 397 } 398 399 402 public boolean equals(Object obj) { 403 if (obj == null) { 404 return false; 405 } 406 if (obj == this) { 407 return true; 408 } 409 if (!(obj instanceof Map )) { 410 return false; 411 } 412 return entrySet().equals(((Map ) obj).entrySet()); 413 } 414 415 418 public int hashCode() { 419 return entrySet().hashCode(); 420 } 421 422 428 public String toString() { 429 StringBuffer buf = new StringBuffer (); 430 buf.append('['); 431 for (Entry pos = sentinel.next; pos != sentinel; pos = pos.next) { 432 buf.append(pos.getKey()); 433 buf.append('='); 434 buf.append(pos.getValue()); 435 if (pos.next != sentinel) { 436 buf.append(','); 437 } 438 } 439 buf.append(']'); 440 return buf.toString(); 441 } 442 443 446 public Set keySet() { 447 return new AbstractSet () { 448 public Iterator iterator() { 450 return new OrderedIterator(KEY); 451 } 452 453 public boolean remove(Object o) { 454 Entry e = SequencedHashMap.this.removeImpl(o); 455 return (e != null); 456 } 457 458 public void clear() { 460 SequencedHashMap.this.clear(); 461 } 462 463 public int size() { 464 return SequencedHashMap.this.size(); 465 } 466 467 public boolean isEmpty() { 468 return SequencedHashMap.this.isEmpty(); 469 } 470 471 public boolean contains(Object o) { 472 return SequencedHashMap.this.containsKey(o); 473 } 474 }; 475 } 476 477 480 public Collection values() { 481 return new AbstractCollection () { 482 public Iterator iterator() { 484 return new OrderedIterator(VALUE); 485 } 486 487 public boolean remove(Object value) { 488 if (value == null) { 492 for (Entry pos = sentinel.next; pos != sentinel; pos = pos.next) { 493 if (pos.getValue() == null) { 494 SequencedHashMap.this.removeImpl(pos.getKey()); 495 return true; 496 } 497 } 498 } else { 499 for (Entry pos = sentinel.next; pos != sentinel; pos = pos.next) { 500 if (value.equals(pos.getValue())) { 501 SequencedHashMap.this.removeImpl(pos.getKey()); 502 return true; 503 } 504 } 505 } 506 return false; 507 } 508 509 public void clear() { 511 SequencedHashMap.this.clear(); 512 } 513 514 public int size() { 515 return SequencedHashMap.this.size(); 516 } 517 518 public boolean isEmpty() { 519 return SequencedHashMap.this.isEmpty(); 520 } 521 522 public boolean contains(Object o) { 523 return SequencedHashMap.this.containsValue(o); 524 } 525 }; 526 } 527 528 531 public Set entrySet() { 532 return new AbstractSet () { 533 private Entry findEntry(Object o) { 535 if (o == null) { 536 return null; 537 } 538 if (!(o instanceof Map.Entry )) { 539 return null; 540 } 541 Map.Entry e = (Map.Entry ) o; 542 Entry entry = (Entry) entries.get(e.getKey()); 543 if ((entry != null) && entry.equals(e)) { 544 return entry; 545 } else { 546 return null; 547 } 548 } 549 550 public Iterator iterator() { 552 return new OrderedIterator(ENTRY); 553 } 554 555 public boolean remove(Object o) { 556 Entry e = findEntry(o); 557 if (e == null) { 558 return false; 559 } 560 return SequencedHashMap.this.removeImpl(e.getKey()) != null; 561 } 562 563 public void clear() { 565 SequencedHashMap.this.clear(); 566 } 567 568 public int size() { 569 return SequencedHashMap.this.size(); 570 } 571 572 public boolean isEmpty() { 573 return SequencedHashMap.this.isEmpty(); 574 } 575 576 public boolean contains(Object o) { 577 return findEntry(o) != null; 578 } 579 }; 580 } 581 582 585 592 public Object clone() throws CloneNotSupportedException { 593 SequencedHashMap map = (SequencedHashMap) super.clone(); 598 599 map.sentinel = createSentinel(); 601 602 map.entries = new HashMap (); 605 606 map.putAll(this); 608 609 return map; 617 } 618 619 625 private Map.Entry getEntry(int index) { 626 Entry pos = sentinel; 627 if (index < 0) { 628 throw new ArrayIndexOutOfBoundsException (index + " < 0"); 629 } 630 631 int i = -1; 633 while ((i < (index - 1)) && (pos.next != sentinel)) { 634 i++; 635 pos = pos.next; 636 } 637 638 if (pos.next == sentinel) { 641 throw new ArrayIndexOutOfBoundsException (index + " >= " + (i + 1)); 642 } 643 return pos.next; 644 } 645 646 652 public Object get(int index) { 653 return getEntry(index).getKey(); 654 } 655 656 662 public Object getValue(int index) { 663 return getEntry(index).getValue(); 664 } 665 666 669 public int indexOf(Object key) { 670 Entry e = (Entry) entries.get(key); 671 int pos = 0; 672 while (e.prev != sentinel) { 673 pos++; 674 e = e.prev; 675 } 676 return pos; 677 } 678 679 682 public Iterator iterator() { 683 return keySet().iterator(); 684 } 685 686 689 public int lastIndexOf(Object key) { 690 return indexOf(key); 692 } 693 694 706 public List sequence() { 707 List l = new ArrayList (size()); 708 Iterator iter = keySet().iterator(); 709 while (iter.hasNext()) { 710 l.add(iter.next()); 711 } 712 return Collections.unmodifiableList(l); 713 } 714 715 723 public Object remove(int index) { 724 return remove(get(index)); 725 } 726 727 729 736 public void readExternal(ObjectInput in) throws IOException , ClassNotFoundException { 737 int size = in.readInt(); 738 for (int i = 0; i < size; i++) { 739 Object key = in.readObject(); 740 Object value = in.readObject(); 741 put(key, value); 742 } 743 } 744 745 751 public void writeExternal(ObjectOutput out) throws IOException { 752 out.writeInt(size()); 753 for (Entry pos = sentinel.next; pos != sentinel; pos = pos.next) { 754 out.writeObject(pos.getKey()); 755 out.writeObject(pos.getValue()); 756 } 757 } 758 759 762 private static class Entry implements Map.Entry { 763 private final Object key; 773 774 private Object value; 775 776 Entry next = null; 779 780 Entry prev = null; 781 782 public Entry(Object key, Object value) { 783 this.key = key; 784 this.value = value; 785 } 786 787 public Object getKey() { 789 return this.key; 790 } 791 792 public Object getValue() { 794 return this.value; 795 } 796 797 public Object setValue(Object value) { 799 Object oldValue = this.value; 800 this.value = value; 801 return oldValue; 802 } 803 804 public int hashCode() { 805 return (((getKey() == null) ? 0 : getKey().hashCode()) ^ 807 ((getValue() == null) ? 0 : getValue().hashCode())); 808 } 809 810 public boolean equals(Object obj) { 811 if (obj == null) { 812 return false; 813 } 814 if (obj == this) { 815 return true; 816 } 817 if (!(obj instanceof Map.Entry )) { 818 return false; 819 } 820 Map.Entry other = (Map.Entry ) obj; 821 822 return (((getKey() == null) ? (other.getKey() == null) : getKey().equals(other.getKey())) && ((getValue() == 824 null) 825 ? 826 (other.getValue() == 827 null) 828 : 829 getValue() 830 .equals(other.getValue()))); 831 } 832 833 public String toString() { 834 return "[" + getKey() + '=' + getValue() + ']'; 835 } 836 } 837 838 private class OrderedIterator implements Iterator { 839 846 private int returnType; 847 848 852 private Entry pos = sentinel; 853 854 858 private transient long expectedModCount = modCount; 859 860 865 public OrderedIterator(int returnType) { 866 this.returnType = returnType | REMOVED_MASK; 876 } 877 878 884 public boolean hasNext() { 885 return pos.next != sentinel; 886 } 887 888 896 public Object next() { 897 if (modCount != expectedModCount) { 898 throw new ConcurrentModificationException (); 899 } 900 if (pos.next == sentinel) { 901 throw new NoSuchElementException (); 902 } 903 904 returnType = returnType & ~REMOVED_MASK; 906 pos = pos.next; 907 switch (returnType) { 908 case KEY: 909 return pos.getKey(); 910 case VALUE: 911 return pos.getValue(); 912 case ENTRY: 913 return pos; 914 default: 915 916 throw new Error ("bad iterator type: " + returnType); 918 } 919 } 920 921 929 public void remove() { 930 if ((returnType & REMOVED_MASK) != 0) { 931 throw new IllegalStateException ("remove() must follow next()"); 932 } 933 if (modCount != expectedModCount) { 934 throw new ConcurrentModificationException (); 935 } 936 SequencedHashMap.this.removeImpl(pos.getKey()); 937 938 expectedModCount++; 940 941 returnType = returnType | REMOVED_MASK; 943 } 944 } 945 } | Popular Tags |