11 " |
11 " |
12 "{ Package: 'stx:libbasic' }" |
12 "{ Package: 'stx:libbasic' }" |
13 |
13 |
14 Collection subclass:#Set |
14 Collection subclass:#Set |
15 instanceVariableNames:'tally keyArray' |
15 instanceVariableNames:'tally keyArray' |
16 classVariableNames:'DeletedEntry' |
16 classVariableNames:'DeletedEntry NilEntry' |
17 poolDictionaries:'' |
17 poolDictionaries:'' |
18 category:'Collections-Unordered' |
18 category:'Collections-Unordered' |
19 ! |
19 ! |
20 |
20 |
21 Object subclass:#EmptySlot |
21 Object subclass:#EmptySlot |
567 ^ true. |
567 ^ true. |
568 |
568 |
569 "Modified: 30.1.1997 / 14:58:08 / cg" |
569 "Modified: 30.1.1997 / 14:58:08 / cg" |
570 ! ! |
570 ! ! |
571 |
571 |
572 !Set methodsFor:'binary storage'! |
|
573 |
|
574 readBinaryContentsFrom: stream manager: manager |
|
575 "must rehash after reload" |
|
576 |
|
577 super readBinaryContentsFrom: stream manager: manager. |
|
578 self rehash |
|
579 ! ! |
|
580 |
572 |
581 !Set methodsFor:'comparing'! |
573 !Set methodsFor:'comparing'! |
582 |
574 |
583 = aCollection |
575 = aCollection |
584 "return true, if the argument is a Set containing the same elements |
576 "return true, if the argument is a Set containing the same elements |
585 as I do" |
577 as I do" |
586 |
578 |
587 aCollection species == self species ifFalse:[^ false]. |
579 aCollection species ~~ self species ifTrue:[^ false]. |
588 aCollection size == self size ifFalse:[^ false]. |
580 aCollection size ~~ self size ifTrue:[^ false]. |
589 "/ same number of elements; since I am a Set, all of |
581 "/ same number of elements; since I am a Set, all of |
590 "/ of my elements must be in the other collection ... |
582 "/ of my elements must be in the other collection ... |
591 ^ self conform:[:element | (aCollection includes:element)] |
583 self do:[:eachElement | (aCollection includes:eachElement) ifFalse:[^ false]]. |
|
584 ^ true. |
592 |
585 |
593 " |
586 " |
594 #(1 2 3 4 5) asSet = #(2 3 4 5 1) asSet |
587 #(1 2 3 4 5) asSet = #(2 3 4 5 1) asSet |
595 #(nil 1 2 3 4 5) asSet = #(2 3 4 5 1) asSet´ |
588 #(nil 1 2 3 4 5) asSet = #(2 3 4 5 1) asSet´ |
596 #(1 2 3 4 5) asSet = #(2 3 4 5 1.0) asSet |
589 #(1 2 3 4 5) asSet = #(2 3 4 5 1.0) asSet |
646 |
639 |
647 "this hash is stupid - but for larger collections, the hashing |
640 "this hash is stupid - but for larger collections, the hashing |
648 time can become much bigger than the time lost in added probing. |
641 time can become much bigger than the time lost in added probing. |
649 Time will show ... |
642 Time will show ... |
650 Notice & warning: |
643 Notice & warning: |
651 if the #= method is ever changed to compare non-dictionaries equal, |
644 if the #= method is ever changed to compare non-dictionaries equal, |
652 the code below must be changed to assert that the same hash-value is |
645 the code below must be changed to assert that the same hash-value is |
653 still returned. |
646 still returned. |
654 (which may be hard to acomplish) |
647 (which may be hard to acomplish) |
655 " |
648 " |
656 |
649 |
657 |mySize| |
650 |mySize| |
658 |
651 |
659 mySize := self size. |
652 mySize := self size. |
660 mySize == 0 ifTrue:[^ 0]. |
653 mySize == 0 ifTrue:[^ 0]. |
661 ^ ((self first) hash times:mySize) bitAnd:16r3FFFFFFF |
654 ^ (self anElement hash times:mySize) bitAnd:16r3FFFFFFF |
662 |
655 |
663 " |
656 " |
664 |d| |
657 |d| |
665 |
658 |
666 d := Dictionary new. |
659 d := Dictionary new. |
834 ! |
815 ! |
835 |
816 |
836 findNil:key |
817 findNil:key |
837 "Look for the next slot usable for key. |
818 "Look for the next slot usable for key. |
838 WARNING: |
819 WARNING: |
839 This method assumes that key is not already in the receiver |
820 This method assumes that key is not already in the receiver |
840 AND that keyArray does not have previously removed entries |
821 AND that keyArray does not have previously removed entries |
841 AND that there is an empty slot. |
822 AND that there is an empty slot. |
842 To be used ONLY while growing/rehashing to enter elements into a fresh |
823 To be used ONLY while growing/rehashing to enter elements into a fresh |
843 collection - if any of the above conditions is not met, the method |
824 collection - if any of the above conditions is not met, the method |
844 loops forever." |
825 loops forever." |
845 |
826 |
846 |index "{ Class:SmallInteger }" |
827 |index "{ Class:SmallInteger }" |
853 "/ index == 0 ifTrue:[ |
834 "/ index == 0 ifTrue:[ |
854 "/ index := keyArray identityIndexOf:nil startingAt:1 endingAt:index. |
835 "/ index := keyArray identityIndexOf:nil startingAt:1 endingAt:index. |
855 "/ ]. |
836 "/ ]. |
856 "/ that code is completely inlined by stc ... |
837 "/ that code is completely inlined by stc ... |
857 [(keyArray basicAt:index) notNil] whileTrue:[ |
838 [(keyArray basicAt:index) notNil] whileTrue:[ |
858 index == length ifTrue:[ |
839 index == length ifTrue:[ |
859 index := 1 |
840 index := 1 |
860 ] ifFalse:[ |
841 ] ifFalse:[ |
861 index := index + 1 |
842 index := index + 1 |
862 ]. |
843 ]. |
863 "notice: no check for no nil found - we must find one since |
844 "notice: no check for no nil found - we must find one since |
864 this is only called after growing" |
845 this is only called after growing" |
865 ]. |
846 ]. |
866 ^ index |
847 ^ index |
867 |
848 |
868 "Modified: 21.3.1997 / 10:32:58 / cg" |
849 "Modified: 21.3.1997 / 10:32:58 / cg" |
869 ! |
850 ! |
883 |index "{ Class:SmallInteger }" |
864 |index "{ Class:SmallInteger }" |
884 length "{ Class:SmallInteger }"| |
865 length "{ Class:SmallInteger }"| |
885 |
866 |
886 length := keyArray basicSize. |
867 length := keyArray basicSize. |
887 index := (self hashFor:aKey) bitAnd:16r3FFFFFFF. |
868 index := (self hashFor:aKey) bitAnd:16r3FFFFFFF. |
888 index < 16r1FFFFFFF ifTrue:[ |
869 |
889 index := index * 2 |
870 "multiply by a large prime to spread the keys over the whole range. |
890 ]. |
871 This causes maxChainLength to reduce from about 2000 to 6 for an |
|
872 IdentitySet of 9000 Smalltalk classes" |
|
873 index := index times:31415821. |
891 index := index \\ length + 1. |
874 index := index \\ length + 1. |
892 ^ index. |
875 ^ index. |
|
876 |
|
877 " |
|
878 Smalltalk allClasses maxChainLength |
|
879 " |
893 |
880 |
894 "Modified: 1.3.1997 / 01:01:13 / cg" |
881 "Modified: 1.3.1997 / 01:01:13 / cg" |
895 "Created: 19.3.1997 / 15:02:41 / cg" |
882 "Created: 19.3.1997 / 15:02:41 / cg" |
896 ! |
883 ! |
897 |
884 |
1083 count := count + (self collisionsFor:eachKey). |
1070 count := count + (self collisionsFor:eachKey). |
1084 ] |
1071 ] |
1085 ]. |
1072 ]. |
1086 |
1073 |
1087 ^ count |
1074 ^ count |
|
1075 |
|
1076 " |
|
1077 self allSubInstances |
|
1078 collect:[:each| each collisionCount -> each] |
|
1079 thenSelect:[:each| each key > 0] |
|
1080 " |
1088 ! |
1081 ! |
1089 |
1082 |
1090 collisionsFor:key |
1083 collisionsFor:key |
1091 "Return the number of searches - 1 required for key" |
1084 "Return the number of searches - 1 required for key" |
1092 |
1085 |
1093 |index "{ Class:SmallInteger }" |
1086 |index "{ Class:SmallInteger }" |
1094 length "{ Class:SmallInteger }" |
1087 length "{ Class:SmallInteger }" startIndex probe count| |
1095 hash "{ Class:SmallInteger }" |
|
1096 step "{ Class:SmallInteger }" |
|
1097 startIndex probe count| |
|
1098 |
1088 |
1099 length := keyArray basicSize. |
1089 length := keyArray basicSize. |
1100 hash := (self hashFor:key) bitAnd:16r3FFFFFFF. |
1090 startIndex := index := self initialIndexForKey:key. |
1101 hash < 16r1FFFFFFF ifTrue:[ |
|
1102 hash := hash * 2 |
|
1103 ]. |
|
1104 startIndex := index := hash \\ length + 1. |
|
1105 step:= hash // length + 1. |
|
1106 |
1091 |
1107 count := 0. |
1092 count := 0. |
1108 [true] whileTrue:[ |
1093 [true] whileTrue:[ |
1109 probe := (keyArray basicAt:index). |
1094 probe := keyArray basicAt:index. |
1110 (probe notNil and:[key = probe]) ifTrue:[^ count]. |
1095 (probe notNil and:[key = probe]) ifTrue:[^ count]. |
1111 (self slotIsEmpty:probe) ifTrue:[self error:'non existing key']. |
1096 (self slotIsEmpty:probe) ifTrue:[self error:'non existing key']. |
1112 |
1097 |
1113 index == length ifTrue:[ |
1098 index == length ifTrue:[ |
1114 index := 1. |
1099 index := 1. |