| 1 19 package bak.pcj.map; 20 21 import bak.pcj.IntCollection; 22 import bak.pcj.AbstractIntCollection; 23 import bak.pcj.IntIterator; 24 import bak.pcj.IntIterator; 25 import bak.pcj.AbstractIntCollection; 26 import bak.pcj.set.AbstractIntSet; 27 import bak.pcj.set.IntSet; 28 import bak.pcj.hash.IntHashFunction; 29 import bak.pcj.hash.DefaultIntHashFunction; 30 import bak.pcj.util.Exceptions; 31 32 import java.io.Serializable ; 33 import java.io.IOException ; 34 import java.io.ObjectInputStream ; 35 import java.io.ObjectOutputStream ; 36 37 48 public class IntKeyIntChainedHashMap extends AbstractIntKeyIntMap implements IntKeyIntMap, Cloneable , Serializable { 49 50 51 private static final int GROWTH_POLICY_RELATIVE = 0; 52 53 54 private static final int GROWTH_POLICY_ABSOLUTE = 1; 55 56 61 private static final int DEFAULT_GROWTH_POLICY = GROWTH_POLICY_RELATIVE; 62 63 64 public static final double DEFAULT_GROWTH_FACTOR = 1.0; 65 66 67 public static final int DEFAULT_GROWTH_CHUNK = 10; 68 69 70 public static final int DEFAULT_CAPACITY = 11; 71 72 73 public static final double DEFAULT_LOAD_FACTOR = 0.75; 74 75 79 private IntHashFunction keyhash; 80 81 85 private int size; 86 87 88 private transient Entry[] data; 89 90 94 private int growthPolicy; 95 96 101 private double growthFactor; 102 103 108 private int growthChunk; 109 110 114 private double loadFactor; 115 116 120 private int expandAt; 121 122 123 private transient IntSet keys; 124 125 126 private transient IntCollection values; 127 128 129 private transient boolean hasLastValue; 130 131 132 private transient int lastValue; 133 134 private IntKeyIntChainedHashMap(IntHashFunction keyhash, int capacity, int growthPolicy, double growthFactor, int growthChunk, double loadFactor) { 135 if (keyhash == null) 136 Exceptions.nullArgument("hash function"); 137 if (capacity < 0) 138 Exceptions.negativeArgument("capacity", String.valueOf(capacity)); 139 if (growthFactor < 0.0) 140 Exceptions.negativeArgument("growthFactor", String.valueOf(growthFactor)); 141 if (growthChunk < 0) 142 Exceptions.negativeArgument("growthChunk", String.valueOf(growthChunk)); 143 if (loadFactor <= 0.0) 144 Exceptions.negativeOrZeroArgument("loadFactor", String.valueOf(loadFactor)); 145 this.keyhash = keyhash; 146 data = new Entry[capacity]; 147 size = 0; 148 expandAt = (int)Math.round(loadFactor*capacity); 149 this.growthPolicy = growthPolicy; 150 this.growthFactor = growthFactor; 151 this.growthChunk = growthChunk; 152 this.loadFactor = loadFactor; 153 hasLastValue = false; 154 } 155 156 private IntKeyIntChainedHashMap(int capacity, int growthPolicy, double growthFactor, int growthChunk, double loadFactor) { 157 this(DefaultIntHashFunction.INSTANCE, capacity, growthPolicy, growthFactor, growthChunk, loadFactor); 158 } 159 160 164 public IntKeyIntChainedHashMap() { 165 this(DEFAULT_CAPACITY); 166 } 167 168 177 public IntKeyIntChainedHashMap(IntKeyIntMap map) { 178 this(); 179 putAll(map); 180 } 181 182 192 public IntKeyIntChainedHashMap(int capacity) { 193 this(capacity, DEFAULT_GROWTH_POLICY, DEFAULT_GROWTH_FACTOR, DEFAULT_GROWTH_CHUNK, DEFAULT_LOAD_FACTOR); 194 } 195 196 206 public IntKeyIntChainedHashMap(double loadFactor) { 207 this(DEFAULT_CAPACITY, DEFAULT_GROWTH_POLICY, DEFAULT_GROWTH_FACTOR, DEFAULT_GROWTH_CHUNK, loadFactor); 208 } 209 210 224 public IntKeyIntChainedHashMap(int capacity, double loadFactor) { 225 this(capacity, DEFAULT_GROWTH_POLICY, DEFAULT_GROWTH_FACTOR, DEFAULT_GROWTH_CHUNK, loadFactor); 226 } 227 228 251 public IntKeyIntChainedHashMap(int capacity, double loadFactor, double growthFactor) { 252 this(capacity, GROWTH_POLICY_RELATIVE, growthFactor, DEFAULT_GROWTH_CHUNK, loadFactor); 253 } 254 255 278 public IntKeyIntChainedHashMap(int capacity, double loadFactor, int growthChunk) { 279 this(capacity, GROWTH_POLICY_ABSOLUTE, DEFAULT_GROWTH_FACTOR, growthChunk, loadFactor); 280 } 281 282 286 296 public IntKeyIntChainedHashMap(IntHashFunction keyhash) { 297 this(keyhash, DEFAULT_CAPACITY, DEFAULT_GROWTH_POLICY, DEFAULT_GROWTH_FACTOR, DEFAULT_GROWTH_CHUNK, DEFAULT_LOAD_FACTOR); 298 } 299 300 316 public IntKeyIntChainedHashMap(IntHashFunction keyhash, int capacity) { 317 this(keyhash, capacity, DEFAULT_GROWTH_POLICY, DEFAULT_GROWTH_FACTOR, DEFAULT_GROWTH_CHUNK, DEFAULT_LOAD_FACTOR); 318 } 319 320 336 public IntKeyIntChainedHashMap(IntHashFunction keyhash, double loadFactor) { 337 this(keyhash, DEFAULT_CAPACITY, DEFAULT_GROWTH_POLICY, DEFAULT_GROWTH_FACTOR, DEFAULT_GROWTH_CHUNK, loadFactor); 338 } 339 340 360 public IntKeyIntChainedHashMap(IntHashFunction keyhash, int capacity, double loadFactor) { 361 this(keyhash, capacity, DEFAULT_GROWTH_POLICY, DEFAULT_GROWTH_FACTOR, DEFAULT_GROWTH_CHUNK, loadFactor); 362 } 363 364 393 public IntKeyIntChainedHashMap(IntHashFunction keyhash, int capacity, double loadFactor, double growthFactor) { 394 this(keyhash, capacity, GROWTH_POLICY_RELATIVE, growthFactor, DEFAULT_GROWTH_CHUNK, loadFactor); 395 } 396 397 426 public IntKeyIntChainedHashMap(IntHashFunction keyhash, int capacity, double loadFactor, int growthChunk) { 427 this(keyhash, capacity, GROWTH_POLICY_ABSOLUTE, DEFAULT_GROWTH_FACTOR, growthChunk, loadFactor); 428 } 429 430 434 private void ensureCapacity(int elements) { 435 if (elements >= expandAt) { 436 int newcapacity; 437 if (growthPolicy == GROWTH_POLICY_RELATIVE) 438 newcapacity = (int)(data.length * (1.0 + growthFactor)); 439 else 440 newcapacity = data.length + growthChunk; 441 if (newcapacity*loadFactor < elements) 442 newcapacity = (int)Math.round(((double)elements/loadFactor)); 443 newcapacity = bak.pcj.hash.Primes.nextPrime(newcapacity); 444 expandAt = (int)Math.round(loadFactor*newcapacity); 445 446 Entry[] newdata = new Entry[newcapacity]; 447 448 for (int i = 0; i < data.length; i++) { 450 Entry e = data[i]; 451 while (e != null) { 452 int index = Math.abs(keyhash.hash(e.key)) % newdata.length; 453 Entry next = e.next; 454 e.next = newdata[index]; 455 newdata[index] = e; 456 e = next; 457 } 458 } 459 460 data = newdata; 461 } 462 } 463 464 private Entry addList(Entry list, Entry v) { 465 v.next = list; 466 return v; 467 } 468 469 private Entry removeList(Entry list, Entry e) { 470 if (list == e) { 471 list = e.next; 472 e.next = null; 473 return list; 474 } 475 Entry listStart = list; 476 while (list.next != e) 477 list = list.next; 478 list.next = e.next; 479 e.next = null; 480 return listStart; 481 } 482 483 private Entry searchList(Entry list, int key) { 484 while (list != null) { 485 if (list.key == key) 486 return list; 487 list = list.next; 488 } 489 return null; 490 } 491 492 private Entry getEntry(int key) { 493 int index = Math.abs(keyhash.hash(key)) % data.length; 494 return searchList(data[index], key); 495 } 496 497 501 public IntSet keySet() { 502 if (keys == null) 503 keys = new KeySet(); 504 return keys; 505 } 506 507 public int lget() { 508 if (!hasLastValue) 509 Exceptions.noLastElement(); 510 return lastValue; 511 } 512 513 public int put(int key, int value) { 514 int result; 515 int index = Math.abs(keyhash.hash(key)) % data.length; 516 Entry e = searchList(data[index], key); 517 if (e == null) { 518 result = MapDefaults.defaultInt(); 519 e = new Entry(key, value); 520 e.next = data[index]; 521 data[index] = e; 522 ensureCapacity(size+1); 525 size++; 526 } else { 527 result = e.value; 528 e.value = value; 529 } 530 return result; 531 } 532 533 public IntCollection values() { 534 if (values == null) 535 values = new ValueCollection(); 536 return values; 537 } 538 539 546 public Object clone() { 547 try { 548 IntKeyIntChainedHashMap c = (IntKeyIntChainedHashMap)super.clone(); 549 c.data = new Entry[data.length]; 550 for (int i = 0; i < data.length; i++) 551 c.data[i] = cloneList(data[i]); 552 c.values = null; 554 c.keys = null; 555 return c; 556 } catch (CloneNotSupportedException e) { 557 Exceptions.cloning(); return null; 558 } 559 } 560 561 private Entry cloneList(Entry e) { 562 if (e == null) 563 return null; 564 Entry ne = new Entry(e.getKey(), e.getValue()); 565 ne.next = cloneList(e.next); 566 return ne; 567 } 568 569 private static class Entry { 570 int key; 571 int value; 572 Entry next; 573 574 Entry(int key, int value) { 575 this.key = key; 576 this.value = value; 577 } 578 579 public int getKey() 580 { return key; } 581 582 public int getValue() 583 { return value; } 584 585 public boolean equals(Object obj) { 586 if (!(obj instanceof Entry)) 587 return false; 588 Entry e = (Entry)obj; 589 return e.getKey() == key && e.getValue() == value; 590 } 591 } 592 593 594 public IntKeyIntMapIterator entries() { 595 return new IntKeyIntMapIterator() { 596 Entry currEntry = null; 597 int nextList = nextList(0); 598 Entry nextEntry = nextList == -1 ? null : data[nextList]; 599 600 int nextList(int index) { 601 while (index < data.length && data[index] == null) 602 index++; 603 return index < data.length ? index : -1; 604 } 605 606 public boolean hasNext() { 607 return nextEntry != null; 608 } 609 610 public void next() { 611 if (nextEntry == null) 612 Exceptions.endOfIterator(); 613 currEntry = nextEntry; 614 615 nextEntry = nextEntry.next; 617 if (nextEntry == null) { 618 nextList = nextList(nextList+1); 619 if (nextList != -1) 620 nextEntry = data[nextList]; 621 } 622 } 623 624 public int getKey() { 625 if (currEntry == null) 626 Exceptions.noElementToGet(); 627 return currEntry.getKey(); 628 } 629 630 public int getValue() { 631 if (currEntry == null) 632 Exceptions.noElementToGet(); 633 return currEntry.getValue(); 634 } 635 636 public void remove() { 637 if (currEntry == null) 638 Exceptions.noElementToRemove(); 639 IntKeyIntChainedHashMap.this.remove(currEntry.getKey()); 640 currEntry = null; 641 } 642 643 }; 644 } 645 646 private class KeySet extends AbstractIntSet { 647 648 public void clear() 649 { IntKeyIntChainedHashMap.this.clear(); } 650 651 public boolean contains(int v) { 652 return getEntry(v) != null; 653 } 654 655 public IntIterator iterator() { 656 return new IntIterator() { 657 Entry currEntry = null; 658 int nextList = nextList(0); 659 Entry nextEntry = nextList == -1 ? null : data[nextList]; 660 661 int nextList(int index) { 662 while (index < data.length && data[index] == null) 663 index++; 664 return index < data.length ? index : -1; 665 } 666 667 public boolean hasNext() { 668 return nextEntry != null; 669 } 670 671 public int next() { 672 if (nextEntry == null) 673 Exceptions.endOfIterator(); 674 currEntry = nextEntry; 675 676 nextEntry = nextEntry.next; 678 if (nextEntry == null) { 679 nextList = nextList(nextList+1); 680 if (nextList != -1) 681 nextEntry = data[nextList]; 682 } 683 return currEntry.key; 684 } 685 686 public void remove() { 687 if (currEntry == null) 688 Exceptions.noElementToRemove(); 689 IntKeyIntChainedHashMap.this.remove(currEntry.getKey()); 690 currEntry = null; 691 } 692 }; 693 } 694 695 public boolean remove(int v) { 696 boolean result = containsKey(v); 697 if (result) 698 IntKeyIntChainedHashMap.this.remove(v); 699 return result; 700 } 701 702 public int size() 703 { return size; } 704 705 } 706 707 708 private class ValueCollection extends AbstractIntCollection { 709 710 public void clear() 711 { IntKeyIntChainedHashMap.this.clear(); } 712 713 public boolean contains(int v) { 714 return containsValue(v); 715 } 716 717 public IntIterator iterator() { 718 return new IntIterator() { 719 Entry currEntry = null; 720 int nextList = nextList(0); 721 Entry nextEntry = nextList == -1 ? null : data[nextList]; 722 723 int nextList(int index) { 724 while (index < data.length && data[index] == null) 725 index++; 726 return index < data.length ? index : -1; 727 } 728 729 public boolean hasNext() { 730 return nextEntry != null; 731 } 732 733 public int next() { 734 if (nextEntry == null) 735 Exceptions.endOfIterator(); 736 currEntry = nextEntry; 737 738 nextEntry = nextEntry.next; 740 if (nextEntry == null) { 741 nextList = nextList(nextList+1); 742 if (nextList != -1) 743 nextEntry = data[nextList]; 744 } 745 return currEntry.value; 746 } 747 748 public void remove() { 749 if (currEntry == null) 750 Exceptions.noElementToRemove(); 751 IntKeyIntChainedHashMap.this.remove(currEntry.getKey()); 752 currEntry = null; 753 } 754 }; 755 } 756 757 public int size() 758 { return size; } 759 760 } 761 762 766 public void clear() { 767 java.util.Arrays.fill(data, null); 768 size = 0; 769 } 770 771 public boolean containsKey(int key) { 772 Entry e = getEntry(key); 773 if (e == null) 774 hasLastValue = false; 775 else { 776 hasLastValue = true; 777 lastValue = e.value; 778 } 779 return hasLastValue; 780 } 781 782 public boolean containsValue(int value) { 783 for (int i = 0; i < data.length; i++) { 784 Entry e = data[i]; 785 while (e != null) { 786 if (e.value == value) 787 return true; 788 e = e.next; 789 } 790 } 791 return false; 792 } 793 794 public int get(int key) { 795 int index = Math.abs(keyhash.hash(key)) % data.length; 796 Entry e = searchList(data[index], key); 797 return e != null ? e.value : MapDefaults.defaultInt(); 798 } 799 800 public boolean isEmpty() 801 { return size == 0; } 802 803 public int remove(int key) { 804 int index = Math.abs(keyhash.hash(key)) % data.length; 805 Entry e = searchList(data[index], key); 806 int value; 807 if (e != null) { 808 data[index] = removeList(data[index], e); 810 value = e.value; 811 size--; 812 } else 813 value = MapDefaults.defaultInt(); 814 return value; 815 } 816 817 public int size() 818 { return size; } 819 820 public int tget(int key) { 821 int index = Math.abs(keyhash.hash(key)) % data.length; 822 Entry e = searchList(data[index], key); 823 if (e == null) 824 Exceptions.noSuchMapping(String.valueOf(key)); 825 return e.value; 826 } 827 828 832 839 private void writeObject(ObjectOutputStream s) throws IOException { 840 s.defaultWriteObject(); 841 s.writeInt(data.length); 842 IntKeyIntMapIterator i = entries(); 843 while (i.hasNext()) { 844 i.next(); 845 s.writeInt(i.getKey()); 846 s.writeInt(i.getValue()); 847 } 848 } 849 850 853 private void readObject(ObjectInputStream s) throws IOException , ClassNotFoundException { 854 s.defaultReadObject(); 855 data = new Entry[s.readInt()]; 856 for (int i = 0; i < size; i++) { 857 int key = s.readInt(); 858 int value = s.readInt(); 859 int index = Math.abs(keyhash.hash(key)) % data.length; 860 Entry e = new Entry(key, value); 861 e.next = data[index]; 862 data[index] = e; 863 } 864 } 865 866 } | Popular Tags |