1 package com.jofti.util; 2 3 import java.util.Arrays ; 4 import java.util.Collection ; 5 import java.util.Collections ; 6 import java.util.HashSet ; 7 import java.util.List ; 8 import java.util.Map ; 9 import java.util.Set ; 10 11 26 27 28 47 48 public class OpenHashMap extends AbstractMap implements Map { 49 50 57 58 protected Object table[]; 59 60 61 62 69 70 protected Object values[]; 71 72 73 74 81 82 protected byte state[]; 83 84 85 86 93 94 protected int freeEntries; 95 96 97 98 99 100 protected static final byte FREE = 0; 101 102 protected static final byte FULL = 1; 103 104 protected static final byte REMOVED = 2; 105 106 107 108 113 114 public OpenHashMap() { 115 116 this(defaultCapacity); 117 118 } 119 120 133 134 public OpenHashMap(int initialCapacity) { 135 136 this(initialCapacity, defaultMinLoadFactor, defaultMaxLoadFactor); 137 138 } 139 140 157 158 public OpenHashMap(int initialCapacity, double minLoadFactor, double maxLoadFactor) { 159 160 setUp(initialCapacity,minLoadFactor,maxLoadFactor); 161 162 } 163 164 165 public OpenHashMap(double minLoadFactor, double maxLoadFactor) { 166 167 setUp(defaultCapacity,minLoadFactor,maxLoadFactor); 168 169 } 170 171 178 179 public void clear() { 180 181 for (int i=0;i<state.length;i++){ 182 state[i] =FREE; 183 } 184 185 for (int i=0;i<values.length;i++){ 186 values[i] =null; 187 } 188 189 190 191 this.distinct = 0; 192 193 this.freeEntries = table.length; 195 trimToSize(); 196 197 } 198 199 208 209 public Object clone() { 210 211 OpenHashMap copy = new OpenHashMap(); 212 213 copy.table = (Object []) copy.table.clone(); 214 215 copy.values = (Object []) copy.values.clone(); 216 217 copy.state = (byte[]) copy.state.clone(); 218 219 return copy; 220 221 } 222 223 232 233 public boolean containsKey(Object key) { 234 235 return indexOfKey(key) >= 0; 236 237 } 238 239 248 249 public boolean containsValue(Object value) { 250 251 return indexOfValue(value) >= 0; 252 253 } 254 255 274 275 public void ensureCapacity(int minCapacity) { 276 277 if (this.highWaterMark < minCapacity) { 278 279 int newCapacity = nextPrime(minCapacity); 280 281 rehash(newCapacity); 282 283 } 284 285 } 286 287 306 307 public boolean forEachKey(ObjectProcedure procedure) { 308 309 for (int i = table.length ; i-- > 0 ;) { 310 311 if (state[i]==FULL) if (! procedure.apply(table[i])) return false; 312 313 } 314 315 return true; 316 317 } 318 319 332 333 public boolean forEachPair(final ObjectProcedure procedure) { 334 335 for (int i = table.length ; i-- > 0 ;) { 336 337 if (state[i]==FULL) if (! procedure.apply(table[i],values[i])) return false; 338 339 } 340 341 return true; 342 343 } 344 345 358 359 public Object get(Object key) { 360 361 if (key ==null){ 362 return null; 363 } 364 int i = indexOfKey(key); 365 366 if (i<0) return null; 368 return values[i]; 369 370 } 371 372 385 386 protected int indexOfInsertion(Object key) { 387 388 final Object tab[] = table; 389 390 final byte stat[] = state; 391 392 final int length = tab.length; 393 394 395 396 final int hash = key.hashCode() & 0x7FFFFFFF; 397 398 int i = hash % length; 399 400 int decrement = hash % (length-2); 402 404 if (decrement == 0) decrement = 1; 405 406 407 408 410 412 while (stat[i] == FULL && (!tab[i].equals(key))) { 413 415 i -= decrement; 416 417 419 if (i<0) i+=length; 420 421 } 422 423 424 425 if (stat[i] == REMOVED) { 426 427 429 431 433 int j = i; 434 435 while (stat[i] != FREE && (stat[i] == REMOVED || (!tab[i].equals(key)))) { 436 i -= decrement; 438 439 441 if (i<0) i+=length; 442 443 } 444 445 if (stat[i] == FREE) i = j; 446 447 } 448 449 450 451 452 453 if (stat[i] == FULL) { 454 455 457 459 return -i-1; 460 461 } 462 463 465 467 return i; 468 469 } 470 471 478 479 protected int indexOfKey(Object key) { 480 481 final Object tab[] = table; 482 483 final byte stat[] = state; 484 485 final int length = tab.length; 486 487 488 489 final int hash = key.hashCode() & 0x7FFFFFFF; 490 491 int i = hash % length; 492 493 int decrement = hash % (length-2); 495 497 if (decrement == 0) decrement = 1; 498 499 500 501 503 505 while (stat[i] != FREE && (stat[i] == REMOVED || !(tab[i].equals(key)))) { 506 508 i -= decrement; 509 510 512 if (i<0) i+=length; 513 514 } 515 516 517 518 if (stat[i] == FREE) return -1; 520 return i; 522 } 523 524 531 532 protected int indexOfValue(Object value) { 533 534 final Object val[] = values; 535 536 final byte stat[] = state; 537 538 539 540 for (int i=stat.length; --i >= 0;) { 541 542 if (stat[i]==FULL && val[i].equals(value)) return i; 543 544 } 545 546 547 548 return -1; 550 } 551 552 569 570 public Object keyOf(Object value) { 571 572 574 int i = indexOfValue(value); 575 576 if (i<0) return null; 577 578 return table[i]; 579 580 } 581 582 601 602 public void keys(Object [] array) { 603 604 605 606 607 608 Object [] tab = table; 609 610 byte[] stat = state; 611 612 613 614 int j=0; 615 616 for (int i = tab.length ; i-- > 0 ;) { 617 618 if (stat[i]==FULL) array[j++]=tab[i]; 619 620 } 621 622 } 623 624 625 626 643 644 public Object put(Object key, Object value) { 645 646 int i = indexOfInsertion(key); 647 648 if (i<0) { 650 i = -i -1; 651 652 Object temp = values[i]; 653 this.values[i]=value; 654 655 return temp; 656 657 } 658 659 660 661 if (this.distinct > this.highWaterMark) { 662 663 int newCapacity = chooseGrowCapacity(this.distinct+1,this.minLoadFactor, this.maxLoadFactor); 664 665 rehash(newCapacity); 666 667 return put(key, value); 668 669 } 670 671 672 673 this.table[i]=key; 674 675 this.values[i]=value; 676 677 if (this.state[i]==FREE) this.freeEntries--; 678 679 this.state[i]=FULL; 680 681 this.distinct++; 682 683 684 685 if (this.freeEntries < 1) { 687 int newCapacity = chooseGrowCapacity(this.distinct+1,this.minLoadFactor, this.maxLoadFactor); 688 689 rehash(newCapacity); 690 691 } 692 693 694 695 return null; 696 697 } 698 699 710 711 protected void rehash(int newCapacity) { 712 713 int oldCapacity = table.length; 714 715 717 718 719 Object oldTable[] = table; 720 721 Object oldValues[] = values; 722 723 byte oldState[] = state; 724 725 726 727 Object newTable[] = new Object [newCapacity]; 728 729 Object newValues[] = new Object [newCapacity]; 730 731 byte newState[] = new byte[newCapacity]; 732 733 734 735 this.lowWaterMark = chooseLowWaterMark(newCapacity,this.minLoadFactor); 736 737 this.highWaterMark = chooseHighWaterMark(newCapacity,this.maxLoadFactor); 738 739 740 741 this.table = newTable; 742 743 this.values = newValues; 744 745 this.state = newState; 746 747 this.freeEntries = newCapacity-this.distinct; 749 750 751 for (int i = oldCapacity ; i-- > 0 ;) { 752 753 if (oldState[i]==FULL) { 754 755 Object element = oldTable[i]; 756 757 int index = indexOfInsertion(element); 758 759 if (index <0){ 760 throw new RuntimeException ("equals and hashCode not implemented correctly - clash when rehashing: "+ element + " and "+ newTable[(Math.abs(index)-1)] + " are equal"); 761 } 762 newTable[index]=element; 763 764 newValues[index]=oldValues[i]; 765 766 newState[index]=FULL; 767 768 } 769 770 } 771 772 } 773 774 785 786 public Object remove(Object key) { 787 788 int i = indexOfKey(key); 789 790 if (i<0) return null; 792 793 794 this.state[i]=REMOVED; 795 796 Object temp =this.values[i]; 797 this.values[i]=null; 799 this.distinct--; 800 801 802 803 if (this.distinct < this.lowWaterMark) { 804 805 int newCapacity = chooseShrinkCapacity(this.distinct,this.minLoadFactor, this.maxLoadFactor); 806 807 rehash(newCapacity); 808 809 } 810 811 812 813 return temp; 814 815 } 816 817 818 public Object removeNoReHash(Object key) { 819 820 int i = indexOfKey(key); 821 822 if (i<0) return null; 824 825 826 this.state[i]=REMOVED; 827 828 Object temp =this.values[i]; 829 this.values[i]=null; 831 this.distinct--; 832 833 834 835 return temp; 836 837 } 838 853 854 protected void setUp(int initialCapacity, double minLoadFactor, double maxLoadFactor) { 855 856 int capacity = initialCapacity; 857 858 super.setUp(capacity, minLoadFactor, maxLoadFactor); 859 860 capacity = nextPrime(capacity); 861 862 if (capacity==0) capacity=1; 864 865 866 this.table = new Object [capacity]; 867 868 this.values = new Object [capacity]; 869 870 this.state = new byte[capacity]; 871 872 873 874 876 this.minLoadFactor = minLoadFactor; 877 878 if (capacity == PrimeFinder.largestPrime) this.maxLoadFactor = 1.0; 879 880 else this.maxLoadFactor = maxLoadFactor; 881 882 883 884 this.distinct = 0; 885 886 this.freeEntries = capacity; 888 889 890 892 894 896 898 this.lowWaterMark = 0; 899 900 this.highWaterMark = chooseHighWaterMark(capacity, this.maxLoadFactor); 901 902 } 903 904 913 914 public void trimToSize() { 915 916 918 920 int newCapacity = nextPrime((int)(1 + 1.2*size())); 921 922 if (table.length > newCapacity) { 923 924 rehash(newCapacity); 925 926 } 927 928 } 929 930 949 950 public void values(Object [] array) { 951 952 953 954 955 956 Object [] val = values; 957 958 byte[] stat = state; 959 960 961 962 int j=0; 963 964 for (int i = stat.length ; i-- > 0 ;) { 965 966 if (stat[i]==FULL) array[j++]=val[i]; 967 968 } 969 970 } 971 972 973 974 public void putAll(Map t) 975 { 976 throw new UnsupportedOperationException ("operation not supported"); 977 978 } 979 980 public Set keySet() 981 { 982 983 throw new UnsupportedOperationException ("operation not supported"); 984 } 985 986 public List keyList() 987 { 988 989 Object [] temp =new Object [state.length - freeEntries]; 990 keys(temp); 991 return Arrays.asList(temp); 992 } 993 994 public Collection values() 995 { 996 997 Object [] temp =new Object [state.length - freeEntries]; 998 values(temp); 999 return Arrays.asList(temp); 1000} 1001 1002public Set entrySet() 1003{ 1004 throw new UnsupportedOperationException ("operation not supported"); 1005} 1006 1007} 1008 1009 1010 | Popular Tags |