| 1 9 package javolution.util; 10 11 import j2me.io.ObjectInputStream; 12 import j2me.io.ObjectOutputStream; 13 import j2me.io.Serializable; 14 import j2me.lang.UnsupportedOperationException; 15 import j2me.util.Collection; 16 import j2me.util.Iterator; 17 import j2me.util.Map; 18 import j2me.util.Set; 19 import j2mex.realtime.MemoryArea; 20 import java.io.IOException ; 21 import java.io.PrintStream ; 22 import javolution.context.PersistentContext; 23 import javolution.context.Realtime; 24 import javolution.context.RealtimeObject; 25 import javolution.lang.Reusable; 26 import javolution.text.Text; 27 import javolution.text.TextBuilder; 28 import javolution.util.FastCollection.Record; 29 import javolution.xml.XMLBinding; 30 import javolution.xml.XMLFormat; 31 import javolution.xml.stream.XMLStreamException; 32 33 93 public class FastMapextends RealtimeObject implements Map, 94 Reusable, Serializable { 95 96 103 protected static final XMLFormatXML = new XMLFormat( 104 new FastMap().getClass()) { 105 106 public void read(InputElement xml, Object obj) 107 throws XMLStreamException { 108 final FastMap fm = (FastMap) obj; 109 fm.setShared(xml.getAttribute("shared", false)); 110 FastComparator keyComparator = (FastComparator) xml 111 .get("KeyComparator"); 112 if (keyComparator != null) { 113 fm.setKeyComparator(keyComparator); 114 } 115 FastComparator valueComparator = (FastComparator) xml 116 .get("ValueComparator"); 117 if (valueComparator != null) { 118 fm.setValueComparator(valueComparator); 119 } 120 while (xml.hasNext()) { 121 Object key = xml.get("Key"); 122 Object value = xml.get("Value"); 123 fm.put(key, value); 124 } 125 } 126 127 public void write(Object obj, OutputElement xml) 128 throws XMLStreamException { 129 final FastMap fm = (FastMap) obj; 130 if (fm.isShared()) { 131 xml.setAttribute("shared", true); 132 } 133 if (fm.getKeyComparator() != FastComparator.DEFAULT) { 134 xml.add(fm.getKeyComparator(), "KeyComparator"); 135 } 136 if (fm.getValueComparator() != FastComparator.DEFAULT) { 137 xml.add(fm.getValueComparator(), "ValueComparator"); 138 } 139 for (Entry e = fm.head(), end = fm.tail(); (e = (Entry) e.getNext()) != end;) { 140 xml.add(e.getKey(), "Key"); 141 xml.add(e.getValue(), "Value"); 142 } 143 } 144 }; 145 146 149 private static final int R0 = 5; 150 151 154 private static final int M0 = (1 << R0) - 1; 155 156 159 private static final Factory FACTORY = new Factory() { 160 161 public Object create() { 162 return new FastMap(); 163 } 164 165 public void cleanup(Object obj) { 166 ((FastMap) obj).reset(); 167 } 168 }; 169 170 174 private transient Entry[][] _entries; 175 176 180 private transient Entry_head; 181 182 186 private transient Entry_tail; 187 188 191 private transient int _size; 192 193 196 private transient Values _values; 197 198 201 private transient KeySet _keySet; 202 203 206 private transient EntrySet _entrySet; 207 208 211 private transient Map_unmodifiable; 212 213 216 private transient FastMap_oldEntries; 217 218 221 private transient FastComparator _keyComparator = FastComparator.DEFAULT; 222 223 226 private transient FastComparator _valueComparator = FastComparator.DEFAULT; 227 228 231 private transient FastComparator _keyComp 232 = FastComparator._Rehash ? FastComparator.REHASH : null; 233 234 237 private transient boolean _isShared; 238 239 242 public FastMap() { 243 this(4); 244 } 245 246 254 public FastMap(String id) { 255 this(); 256 new PersistentContext.Reference(id, this) { 257 protected void notifyChange() { 258 FastMap.this.clear(); 259 FastMap.this.putAll((FastMap) this.get()); 260 } 261 }; 262 } 263 264 271 public FastMap(int capacity) { 272 setup(capacity); 273 } 274 private void setup(int capacity) { 275 int tableLength = 1 << R0; 276 while (tableLength < capacity) { 277 tableLength <<= 1; 278 } 279 _entries = (Entry[][]) new Entry[tableLength >> R0][]; 280 for (int i = 0; i < _entries.length;) { 281 _entries[i++] = (Entry[]) new Entry[1 << R0]; 282 } 283 _head = new Entry(); 284 _tail = new Entry(); 285 _head._next = _tail; 286 _tail._previous = _head; 287 Entryprevious = _tail; 288 for (int i = 0; i++ < capacity;) { 289 EntrynewEntry = new Entry(); 290 newEntry._previous = previous; 291 previous._next = newEntry; 292 previous = newEntry; 293 } 294 } 295 296 302 public FastMap(Mapmap) { 303 this(map.size()); 304 putAll(map); 305 } 306 307 312 private FastMap(Entry[][] entries) { 313 _head = new Entry(); 314 _tail = new Entry(); 315 _head._next = _tail; 316 _tail._previous = _head; 317 _entries = entries; 318 } 319 320 327 public staticFastMapnewInstance() { 328 return (FastMap) FACTORY.object(); 329 } 330 331 336 public static void recycle(FastMap instance) { 337 FACTORY.recycle(instance); 338 } 339 340 346 public final Entryhead() { 347 return _head; 348 } 349 350 356 public final Entrytail() { 357 return _tail; 358 } 359 360 365 public final int size() { 366 return _size; 367 } 368 369 375 public final boolean isEmpty() { 376 return _head._next == _tail; 377 } 378 379 387 public final boolean containsKey(Object key) { 388 return getEntry(key) != null; 389 } 390 391 399 public final boolean containsValue(Object value) { 400 return values().contains(value); 401 } 402 403 411 public final Object get(Object key) { 412 Entryentry = getEntry(key, (_keyComp == null) ? key 413 .hashCode() : _keyComp.hashCodeOf(key)); 414 return (entry != null) ? entry._value : null; 415 } 416 417 423 public final EntrygetEntry(Object key) { 424 return getEntry(key, (_keyComp == null) ? key.hashCode() : _keyComp 425 .hashCodeOf(key)); 426 } 427 428 442 public final Object put(Object key, Object value) { 443 final int keyHash = (_keyComp == null) ? key.hashCode() : _keyComp 444 .hashCodeOf(key); 445 Entryentry = getEntry(key, keyHash); 446 if (entry != null) { 447 Object prevValue = entry._value; 448 entry._value = value; 449 return prevValue; 450 } 451 if (_isShared) return putShared(key, value, keyHash); 453 addEntry(keyHash, key, value); 454 return null; 455 } 456 457 private synchronized Object putShared(Object key, 458 Object value, int keyHash) { 459 Entryentry = getEntry(key, keyHash); if (entry == null) { addEntry(keyHash, key, value); 462 return null; 463 } 464 Object prevValue = entry._value; 465 entry._value = value; 466 return prevValue; 467 } 468 469 476 public final void putAll(Mapmap) { 477 if (map instanceof FastMap) { FastMapfm = (FastMap) map; 479 for (Entrye = fm._head, end = fm._tail; (e = e._next) != end;) { 480 put(e._key, e._value); 481 } 482 } else { 483 for (Iterator i = map.entrySet().iterator(); i.hasNext();) { 484 Map.Entrye = (Map.Entry) i 485 .next(); 486 put(e.getKey(), e.getValue()); 487 } 488 } 489 } 490 491 508 public final Object remove(Object key) { 509 Entryentry = getEntry(key); 510 if (entry == null) 511 return null; 512 if (_isShared) return removeShared(entry); 514 Object prevValue = entry._value; 515 removeEntry(entry); 516 return prevValue; 517 } 518 519 private synchronized Object removeShared(Entryentry) { 520 _size--; 521 entry.detach(); 522 return entry._value; 523 } 524 525 541 public FastMapsetShared(boolean isShared) { 542 _isShared = isShared; 543 return this; 544 } 545 546 553 public boolean isShared() { 554 return _isShared; 555 } 556 557 563 public FastMapsetKeyComparator(FastComparator keyComparator) { 564 _keyComparator = keyComparator; 565 _keyComp = (keyComparator instanceof FastComparator.Default) ? 566 (FastComparator._Rehash ? FastComparator.REHASH : null) 567 : (keyComparator instanceof FastComparator.Direct) ? null 568 : keyComparator; 569 return this; 570 } 571 572 577 public FastComparator getKeyComparator() { 578 return _keyComparator; 579 } 580 581 587 public FastMapsetValueComparator(FastComparator valueComparator) { 588 _valueComparator = valueComparator; 589 return this; 590 } 591 592 597 public FastComparator getValueComparator() { 598 return _valueComparator; 599 } 600 601 611 public final void clear() { 612 if (_isShared) { 613 clearShared(); 614 return; 615 } 616 for (Entrye = _head, end = _tail; (e = e._next) != end;) { 618 e._key = null; 619 e._value = null; 620 final Entry[][] table = e._table; 621 table[(e._keyHash >> R0) & (table.length - 1)][e._keyHash & M0] = null; 622 } 623 _tail = _head._next; 624 _size = 0; 625 626 _oldEntries = null; 628 } 629 630 private synchronized void clearShared() { 631 for (Entrye = _head, end = _tail; (e = e._next) != end;) { 632 final Entry[][] table = e._table; 633 table[(e._keyHash >> R0) & (table.length - 1)][e._keyHash & M0] = null; 634 } 635 _head._next = _tail; _tail._previous = _head; _oldEntries = null; 638 _size = 0; 639 } 640 641 651 public boolean equals(Object obj) { 652 if (obj == this) { 653 return true; 654 } else if (obj instanceof Map) { 655 Mapthat = (Map) obj; 656 return this.entrySet().equals(that.entrySet()); 657 } else { 658 return false; 659 } 660 } 661 662 667 public int hashCode() { 668 int code = 0; 669 for (Entry e = _head, end = _tail; (e = e._next) != end;) { 670 code += e.hashCode(); 671 } 672 return code; 673 } 674 675 680 public Text toText() { 681 return Text.valueOf(entrySet()); 682 } 683 684 692 public void printStatistics(PrintStream out) { 693 int maxOccupancy = 0; 694 int totalCollisions = 0; 695 int size = 0; 696 for (int i = 0; i < _entries.length; i++) { 697 for (int j = 0; j < _entries[i].length; j++) { 698 Entry entry = _entries[i][j]; 699 int occupancy = 0; 700 while (entry != null) { 701 occupancy++; 702 if (occupancy > maxOccupancy) { 703 maxOccupancy = occupancy; 704 } 705 if (occupancy > 1) { 706 totalCollisions++; 707 } 708 entry = entry._beside; 709 size++; 710 } 711 } 712 } 713 TextBuilder percentCollisions = TextBuilder.newInstance(); 714 if (size != 0) { 715 percentCollisions.append((100 * totalCollisions) / size); 716 percentCollisions.append('%'); 717 } else { 718 percentCollisions.append("N/A"); 719 } 720 synchronized (out) { 721 out.print("SIZE: " + size); 722 out 723 .print(", TABLE LENGTH: " + _entries.length 724 * _entries[0].length); 725 out.print(", AVG COLLISIONS: " + percentCollisions); 726 out.print(", MAX SLOT OCCUPANCY: " + maxOccupancy); 727 out.print(", KEY COMPARATOR: " 728 + ((_keyComp == null) ? FastComparator.DIRECT : _keyComp)); 729 out.print(", SHARED: " + _isShared); 730 out.println(); 731 if (_oldEntries != null) { 732 out.print(" + "); 733 _oldEntries.printStatistics(out); 734 } 735 } 736 } 737 738 752 public final Collectionvalues() { 753 if (_values == null) { 754 MemoryArea.getMemoryArea(this).executeInArea(new Runnable () { 755 public void run() { 756 _values = new Values(); 757 } 758 }); 759 } 760 return _values; 761 } 762 763 private final class Values extends FastCollection { 764 765 public int size() { 766 return _size; 767 } 768 769 public void clear() { 770 FastMap.this.clear(); 771 } 772 773 public Record head() { 774 return FastMap.this._head; 775 } 776 777 public Record tail() { 778 return FastMap.this._tail; 779 } 780 781 public Object valueOf(Record record) { 782 return ((Entry) record)._value; 783 } 784 785 public void delete(Record record) { 786 FastMap.this.remove(((Entry) record).getKey()); 787 } 788 789 public FastComparator getValueComparator() { 790 return _valueComparator; 791 } 792 } 793 794 808 public final SetentrySet() { 809 if (_entrySet == null) { 810 MemoryArea.getMemoryArea(this).executeInArea(new Runnable () { 811 public void run() { 812 _entrySet = new EntrySet(); 813 } 814 }); 815 } 816 return _entrySet; 817 } 818 819 private final class EntrySet extends FastCollection implements Set { 820 821 public int size() { 822 return _size; 823 } 824 825 public void clear() { 826 FastMap.this.clear(); 827 } 828 829 public boolean contains(Object obj) { if (obj instanceof Map.Entry) { 831 Map.Entry thatEntry = (Entry) obj; 832 Entry thisEntry = getEntry(thatEntry.getKey()); 833 if (thisEntry == null) return false; 834 return _valueComparator.areEqual(thisEntry.getValue(), thatEntry.getValue()); 835 } else { 836 return false; 837 } 838 } 839 840 public Text toText() { 841 Text text = Text.valueOf('['); 842 final Text equ = Text.valueOf('='); 843 final Text sep = Text.valueOf(", "); 844 for (Entry e = _head, end = _tail; (e = e._next) != end;) { 845 text = text.concat(Text.valueOf(e._key)).concat(equ).concat( 846 Text.valueOf(e._value)); 847 if (e._next != end) { 848 text = text.concat(sep); 849 } 850 } 851 return text.concat(Text.valueOf(']')); 852 } 853 854 public Record head() { 855 return _head; 856 } 857 858 public Record tail() { 859 return _tail; 860 } 861 862 public Object valueOf(Record record) { 863 return (Map.Entry) record; 864 } 865 866 public void delete(Record record) { 867 FastMap.this.remove(((Entry) record).getKey()); 868 } 869 870 public FastComparator getValueComparator() { 871 return _entryComparator; 872 } 873 private final FastComparator _entryComparator = new FastComparator() { 874 875 public boolean areEqual(Object o1, Object o2) { 876 if ((o1 instanceof Map.Entry) && (o2 instanceof Map.Entry)) { 877 Map.Entry e1 = (Map.Entry) o1; 878 Map.Entry e2 = (Map.Entry) o2; 879 return _keyComparator.areEqual(e1.getKey(), e2.getKey()) && 880 _valueComparator.areEqual(e1.getValue(), e2.getValue()); 881 } 882 return (o1 == null) && (o2 == null); 883 } 884 885 public int compare(Object o1, Object o2) { 886 return _keyComparator.compare(o1, o2); 887 } 888 889 public int hashCodeOf(Object obj) { 890 Map.Entry entry = (Map.Entry) obj; 891 return _keyComparator.hashCodeOf(entry.
|