| 1 19 package bak.pcj.map; 20 21 import bak.pcj.LongIterator; 22 import bak.pcj.AbstractLongCollection; 23 import bak.pcj.set.AbstractLongSet; 24 import bak.pcj.set.LongSet; 25 import bak.pcj.hash.LongHashFunction; 26 import bak.pcj.hash.DefaultLongHashFunction; 27 import bak.pcj.util.Exceptions; 28 29 import java.util.Collection ; 30 import java.util.AbstractCollection ; 31 import java.util.Iterator ; 32 33 import java.io.Serializable ; 34 import java.io.IOException ; 35 import java.io.ObjectInputStream ; 36 import java.io.ObjectOutputStream ; 37 38 49 public class LongKeyOpenHashMap extends AbstractLongKeyMap implements LongKeyMap, Cloneable , Serializable { 50 51 52 private static final int GROWTH_POLICY_RELATIVE = 0; 53 54 55 private static final int GROWTH_POLICY_ABSOLUTE = 1; 56 57 62 private static final int DEFAULT_GROWTH_POLICY = GROWTH_POLICY_RELATIVE; 63 64 65 public static final double DEFAULT_GROWTH_FACTOR = 1.0; 66 67 68 public static final int DEFAULT_GROWTH_CHUNK = 10; 69 70 71 public static final int DEFAULT_CAPACITY = 11; 72 73 74 public static final double DEFAULT_LOAD_FACTOR = 0.75; 75 76 80 private LongHashFunction keyhash; 81 82 86 private int size; 87 88 93 private transient long[] keys; 94 95 100 private transient Object [] values; 101 102 103 private transient byte[] states; 104 105 private static final byte EMPTY = 0; 106 private static final byte OCCUPIED = 1; 107 private static final byte REMOVED = 2; 108 109 110 private transient int used; 111 112 116 private int growthPolicy; 117 118 123 private double growthFactor; 124 125 130 private int growthChunk; 131 132 136 private double loadFactor; 137 138 142 private int expandAt; 143 144 145 private transient LongSet ckeys; 146 147 148 private transient Collection cvalues; 149 150 private LongKeyOpenHashMap(LongHashFunction keyhash, int capacity, int growthPolicy, double growthFactor, int growthChunk, double loadFactor) { 151 if (keyhash == null) 152 Exceptions.nullArgument("hash function"); 153 if (capacity < 0) 154 Exceptions.negativeArgument("capacity", String.valueOf(capacity)); 155 if (growthFactor <= 0.0) 156 Exceptions.negativeOrZeroArgument("growthFactor", String.valueOf(growthFactor)); 157 if (growthChunk <= 0) 158 Exceptions.negativeOrZeroArgument("growthChunk", String.valueOf(growthChunk)); 159 if (loadFactor <= 0.0) 160 Exceptions.negativeOrZeroArgument("loadFactor", String.valueOf(loadFactor)); 161 this.keyhash = keyhash; 162 capacity = bak.pcj.hash.Primes.nextPrime(capacity); 163 keys = new long[capacity]; 164 values = new Object [capacity]; 165 this.states = new byte[capacity]; 166 size = 0; 167 expandAt = (int)Math.round(loadFactor*capacity); 168 this.used = 0; 169 this.growthPolicy = growthPolicy; 170 this.growthFactor = growthFactor; 171 this.growthChunk = growthChunk; 172 this.loadFactor = loadFactor; 173 } 174 175 private LongKeyOpenHashMap(int capacity, int growthPolicy, double growthFactor, int growthChunk, double loadFactor) { 176 this(DefaultLongHashFunction.INSTANCE, capacity, growthPolicy, growthFactor, growthChunk, loadFactor); 177 } 178 179 183 public LongKeyOpenHashMap() { 184 this(DEFAULT_CAPACITY); 185 } 186 187 196 public LongKeyOpenHashMap(LongKeyMap map) { 197 this(); 198 putAll(map); 199 } 200 201 211 public LongKeyOpenHashMap(int capacity) { 212 this(capacity, DEFAULT_GROWTH_POLICY, DEFAULT_GROWTH_FACTOR, DEFAULT_GROWTH_CHUNK, DEFAULT_LOAD_FACTOR); 213 } 214 215 226 public LongKeyOpenHashMap(double loadFactor) { 227 this(DEFAULT_CAPACITY, DEFAULT_GROWTH_POLICY, DEFAULT_GROWTH_FACTOR, DEFAULT_GROWTH_CHUNK, loadFactor); 228 } 229 230 244 public LongKeyOpenHashMap(int capacity, double loadFactor) { 245 this(capacity, DEFAULT_GROWTH_POLICY, DEFAULT_GROWTH_FACTOR, DEFAULT_GROWTH_CHUNK, loadFactor); 246 } 247 248 271 public LongKeyOpenHashMap(int capacity, double loadFactor, double growthFactor) { 272 this(capacity, GROWTH_POLICY_RELATIVE, growthFactor, DEFAULT_GROWTH_CHUNK, loadFactor); 273 } 274 275 298 public LongKeyOpenHashMap(int capacity, double loadFactor, int growthChunk) { 299 this(capacity, GROWTH_POLICY_ABSOLUTE, DEFAULT_GROWTH_FACTOR, growthChunk, loadFactor); 300 } 301 302 306 316 public LongKeyOpenHashMap(LongHashFunction keyhash) { 317 this(keyhash, DEFAULT_CAPACITY, DEFAULT_GROWTH_POLICY, DEFAULT_GROWTH_FACTOR, DEFAULT_GROWTH_CHUNK, DEFAULT_LOAD_FACTOR); 318 } 319 320 336 public LongKeyOpenHashMap(LongHashFunction keyhash, int capacity) { 337 this(keyhash, capacity, DEFAULT_GROWTH_POLICY, DEFAULT_GROWTH_FACTOR, DEFAULT_GROWTH_CHUNK, DEFAULT_LOAD_FACTOR); 338 } 339 340 357 public LongKeyOpenHashMap(LongHashFunction keyhash, double loadFactor) { 358 this(keyhash, DEFAULT_CAPACITY, DEFAULT_GROWTH_POLICY, DEFAULT_GROWTH_FACTOR, DEFAULT_GROWTH_CHUNK, loadFactor); 359 } 360 361 381 public LongKeyOpenHashMap(LongHashFunction keyhash, int capacity, double loadFactor) { 382 this(keyhash, capacity, DEFAULT_GROWTH_POLICY, DEFAULT_GROWTH_FACTOR, DEFAULT_GROWTH_CHUNK, loadFactor); 383 } 384 385 414 public LongKeyOpenHashMap(LongHashFunction keyhash, int capacity, double loadFactor, double growthFactor) { 415 this(keyhash, capacity, GROWTH_POLICY_RELATIVE, growthFactor, DEFAULT_GROWTH_CHUNK, loadFactor); 416 } 417 418 447 public LongKeyOpenHashMap(LongHashFunction keyhash, int capacity, double loadFactor, int growthChunk) { 448 this(keyhash, capacity, GROWTH_POLICY_ABSOLUTE, DEFAULT_GROWTH_FACTOR, growthChunk, loadFactor); 449 } 450 451 455 private void ensureCapacity(int elements) { 456 if (elements >= expandAt) { 457 int newcapacity; 458 if (growthPolicy == GROWTH_POLICY_RELATIVE) 459 newcapacity = (int)(keys.length * (1.0 + growthFactor)); 460 else 461 newcapacity = keys.length + growthChunk; 462 if (newcapacity*loadFactor < elements) 463 newcapacity = (int)Math.round(((double)elements/loadFactor)); 464 newcapacity = bak.pcj.hash.Primes.nextPrime(newcapacity); 465 expandAt = (int)Math.round(loadFactor*newcapacity); 466 467 long[] newkeys = new long[newcapacity]; 468 Object [] newvalues = new Object [newcapacity]; 469 byte[] newstates = new byte[newcapacity]; 470 471 used = 0; 472 for (int i = 0; i < keys.length; i++) { 474 if (states[i] == OCCUPIED) { 475 used++; 476 long k = keys[i]; 477 Object v = values[i]; 478 int h = Math.abs(keyhash.hash(k)); 480 int n = h % newcapacity; 481 if (newstates[n] == OCCUPIED) { 482 int c = 1 + (h % (newcapacity - 2)); 484 for (;;) { 485 n -= c; 486 if (n < 0) 487 n += newcapacity; 488 if (newstates[n] == EMPTY) 489 break; 490 } 491 } 492 newstates[n] = OCCUPIED; 493 newvalues[n] = v; 494 newkeys[n] = k; 495 } 496 } 497 498 keys = newkeys; 499 values = newvalues; 500 states = newstates; 501 } 502 } 503 504 508 public LongSet keySet() { 509 if (ckeys == null) 510 ckeys = new KeySet(); 511 return ckeys; 512 } 513 514 public Object put(long key, Object value) { 515 Object result; 516 517 int h = Math.abs(keyhash.hash(key)); 519 int i = h % keys.length; 520 if (states[i] == OCCUPIED) { 521 if (keys[i] == key) { 522 Object oldValue = values[i]; 523 values[i] = value; 524 return oldValue; 525 } 526 int c = 1 + (h % (keys.length - 2)); 528 for (;;) { 529 i -= c; 530 if (i < 0) 531 i += keys.length; 532 if (states[i] == EMPTY || states[i] == REMOVED) 534 break; 535 if (states[i] == OCCUPIED && keys[i] == key) { 536 Object oldValue = values[i]; 537 values[i] = value; 538 return oldValue; 539 } 540 } 541 } 542 543 if (states[i] == EMPTY) 544 used++; 545 states[i] = OCCUPIED; 546 keys[i] = key; 547 values[i] = value; 548 size++; 549 ensureCapacity(used); 550 return null; 551 } 552 553 public Collection values() { 554 if (cvalues == null) 555 cvalues = new ValueCollection(); 556 return cvalues; 557 } 558 559 566 public Object clone() { 567 try { 568 LongKeyOpenHashMap c = (LongKeyOpenHashMap)super.clone(); 569 c.keys = new long[keys.length]; 570 System.arraycopy(keys, 0, c.keys, 0, keys.length); 571 c.values = new Object [values.length]; 572 System.arraycopy(values, 0, c.values, 0, values.length); 573 c.states = new byte[states.length]; 574 System.arraycopy(states, 0, c.states, 0, states.length); 575 c.cvalues = null; 577 c.ckeys = null; 578 return c; 579 } catch (CloneNotSupportedException e) { 580 Exceptions.cloning(); return null; 581 } 582 } 583 584 public LongKeyMapIterator entries() { 585 return new LongKeyMapIterator() { 586 int nextEntry = nextEntry(0); 587 int lastEntry = -1; 588 589 int nextEntry(int index) { 590 while (index < keys.length && states[index] != OCCUPIED) 591 index++; 592 return index; 593 } 594 595 public boolean hasNext() { 596 return nextEntry < keys.length; 597 } 598 599 public void next() { 600 if (!hasNext()) 601 Exceptions.endOfIterator(); 602 lastEntry = nextEntry; 603 nextEntry = nextEntry(nextEntry+1); 604 } 605 606 public void remove() { 607 if (lastEntry == -1) 608 Exceptions.noElementToRemove(); 609 states[lastEntry] = REMOVED; 610 values[lastEntry] = null; size--; 612 lastEntry = -1; 613 } 614 615 public long getKey() { 616 if (lastEntry == -1) 617 Exceptions.noElementToGet(); 618 return keys[lastEntry]; 619 } 620 621 public Object getValue() { 622 if (lastEntry == -1) 623 Exceptions.noElementToGet(); 624 return values[lastEntry]; 625 } 626 }; 627 } 628 629 private class KeySet extends AbstractLongSet { 630 631 public void clear() 632 { LongKeyOpenHashMap.this.clear(); } 633 634 public boolean contains(long v) { 635 return containsKey(v); 636 } 637 638 public LongIterator iterator() { 639 return new LongIterator() { 640 int nextEntry = nextEntry(0); 641 int lastEntry = -1; 642 643 int nextEntry(int index) { 644 while (index < keys.length && states[index] != OCCUPIED) 645 index++; 646 return index; 647 } 648 649 public boolean hasNext() { 650 return nextEntry < keys.length; 651 } 652 653 public long next() { 654 if (!hasNext()) 655 Exceptions.endOfIterator(); 656 lastEntry = nextEntry; 657 nextEntry = nextEntry(nextEntry+1); 658 return keys[lastEntry]; 659 } 660 661 public void remove() { 662 if (lastEntry == -1) 663 Exceptions.noElementToRemove(); 664 states[lastEntry] = REMOVED; 665 values[lastEntry] = null; size--; 667 lastEntry = -1; 668 } 669 }; 670 } 671 672 public boolean remove(long v) { 673 boolean result = containsKey(v); 674 if (result) 675 LongKeyOpenHashMap.this.remove(v); 676 return result; 677 } 678 679 public int size() 680 { return size; } 681 682 } 683 684 685 private class ValueCollection extends AbstractCollection { 686 687 public void clear() 688 { LongKeyOpenHashMap.this.clear(); } 689 690 public boolean contains(Object v) { 691 return containsValue(v); 692 } 693 694 public Iterator iterator() { 695 return new Iterator() { 696 int nextEntry = nextEntry(0); 697 int lastEntry = -1; 698 699 int nextEntry(int index) { 700 while (index < keys.length && states[index] != OCCUPIED) 701 index++; 702 return index; 703 } 704 705 public boolean hasNext() { 706 return nextEntry < keys.length; 707 } 708 709 public Object next() { 710 if (!hasNext()) 711 Exceptions.endOfIterator(); 712 lastEntry = nextEntry; 713 nextEntry = nextEntry(nextEntry+1); 714 return values[lastEntry]; 715 } 716 717 public void remove() { 718 if (lastEntry == -1) 719 Exceptions.noElementToRemove(); 720 states[lastEntry] = REMOVED; 721 values[lastEntry] = null; size--; 723 lastEntry = -1; 724 } 725 }; 726 } 727 728 public int size() 729 { return size; } 730 731 } 732 733 737 public void clear() { 738 java.util.Arrays.fill(states, EMPTY); 739 java.util.Arrays.fill(values, null); size = 0; 741 used = 0; 742 } 743 744 public boolean containsKey(long key) { 745 int h = Math.abs(keyhash.hash(key)); 746 int i = h % keys.length; 747 if (states[i] != EMPTY) { 748 if (states[i] == OCCUPIED && keys[i] == key) 749 return true; 750 751 int c = 1 + (h % (keys.length - 2)); 753 for (;;) { 754 i -= c; 755 if (i < 0) 756 i += keys.length; 757 if (states[i] == EMPTY) 758 return false; 759 if (states[i] == OCCUPIED && keys[i] == key) 760 return true; 761 } 762 } 763 return false; 764 } 765 766 public boolean containsValue(Object value) { 767 if (value == null) { 768 for (int i = 0; i < states.length; i++) 769 if (states[i] == OCCUPIED && values[i] == null) 770 return true; 771 } else { 772 for (int i = 0; i < states.length; i++) 773 if (states[i] == OCCUPIED && value.equals(values[i])) 774 return true; 775 } 776 return false; 777 } 778 779 public Object get(long key) { 780 int h = Math.abs(keyhash.hash(key)); 781 int i = h % keys.length; 782 if (states[i] != EMPTY) { 783 if (states[i] == OCCUPIED && keys[i] == key) 784 return values[i]; 785 787 int c = 1 + (h % (keys.length - 2)); 788 for (;;) { 789 i -= c; 790 if (i < 0) 791 i += keys.length; 792 if (states[i] == EMPTY) 793 return null; 794 if (states[i] == OCCUPIED && keys[i] == key) 795 return values[i]; 796 } 797 } 798 return null; 799 } 800 801 public boolean isEmpty() 802 { return size == 0; } 803 804 public Object remove(long key) { 805 int h = Math.abs(keyhash.hash(key)); 806 int i = h % keys.length; 807 if (states[i] != EMPTY) { 808 if (states[i] == OCCUPIED && keys[i] == key) { 809 Object oldValue = values[i]; 810 values[i] = null; states[i] = REMOVED; 812 size--; 813 return oldValue; 814 } 815 int c = 1 + (h % (keys.length - 2)); 817 for (;;) { 818 i -= c; 819 if (i < 0) 820 i += keys.length; 821 if (states[i] == EMPTY) { 822 return null; 823 } 824 if (states[i] == OCCUPIED && keys[i] == key) { 825 Object oldValue = values[i]; 826 values[i] = null; states[i] = REMOVED; 828 size--; 829 return oldValue; 830 } 831 } 832 } 833 return null; 834 } 835 836 public int size() 837 { return size; } 838 839 843 850 private void writeObject(ObjectOutputStream s) throws IOException { 851 s.defaultWriteObject(); 852 s.writeInt(keys.length); 853 LongKeyMapIterator i = entries(); 854 while (i.hasNext()) { 855 i.next(); 856 s.writeLong(i.getKey()); 857 s.writeObject(i.getValue()); 858 } 859 } 860 861 864 private void readObject(ObjectInputStream s) throws IOException , ClassNotFoundException { 865 s.defaultReadObject(); 866 keys = new long[s.readInt()]; 867 states = new byte[keys.length]; 868 values = new Object [keys.length]; 869 used = size; 870 871 for (int n = 0; n < size; n++) { 872 long key = s.readLong(); 873 Object value = s.readObject(); 874 875 int h = Math.abs(keyhash.hash(key)); 877 int i = h % keys.length; 878 if (states[i] != EMPTY) { 879 int c = 1 + (h % (keys.length - 2)); 881 for (;;) { 882 i -= c; 883 if (i < 0) 884 i += keys.length; 885 if (states[i] == EMPTY) 886 break; 887 } 888 } 889 states[i] = OCCUPIED; 890 keys[i] = key; 891 values[i] = value; 892 } 893 } 894 895 } | Popular Tags |