1 ! Copyright (C) 2005, 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays kernel kernel.private slots.private math
4 assocs math.private sequences sequences.private vectors ;
8 { count array-capacity }
9 { deleted array-capacity }
14 : wrap ( i array -- n )
15 length>> 1 fixnum-fast fixnum-bitand ; inline
17 : hash@ ( key array -- i )
18 [ hashcode >fixnum dup fixnum+fast ] dip wrap ; inline
20 : probe ( array i -- array i )
21 2 fixnum+fast over wrap ; inline
23 : no-key ( key array -- array n ? ) nip f f ; inline
25 : (key@) ( key array i -- array n ? )
29 = [ rot drop t ] [ probe (key@) ] if
30 ] if ; inline recursive
32 : key@ ( key hash -- array n ? )
33 array>> dup length>> 0 eq?
34 [ no-key ] [ 2dup hash@ (key@) ] if ; inline
36 : <hash-array> ( n -- array )
37 1+ next-power-of-2 4 * ((empty)) <array> ; inline
39 : init-hash ( hash -- )
40 0 >>count 0 >>deleted drop ; inline
42 : reset-hash ( n hash -- )
43 swap <hash-array> >>array init-hash ; inline
45 : (new-key@) ( key keys i -- keys n empty? )
46 3dup swap array-nth dup ((empty)) eq? [
54 ] if ; inline recursive
56 : new-key@ ( key hash -- array n empty? )
57 array>> 2dup hash@ (new-key@) ; inline
59 : set-nth-pair ( value key seq n -- )
60 2 fixnum+fast [ set-slot ] 2keep
61 1 fixnum+fast set-slot ; inline
63 : hash-count+ ( hash -- )
64 [ 1+ ] change-count drop ; inline
66 : hash-deleted+ ( hash -- )
67 [ 1+ ] change-deleted drop ; inline
69 : (rehash) ( hash alist -- )
70 swap [ swapd set-at ] curry assoc-each ; inline
72 : hash-large? ( hash -- ? )
73 [ count>> 3 fixnum*fast 1 fixnum+fast ]
74 [ array>> length>> ] bi fixnum> ; inline
76 : hash-stale? ( hash -- ? )
77 [ deleted>> 10 fixnum*fast ] [ count>> ] bi fixnum> ; inline
79 : grow-hash ( hash -- )
80 [ [ >alist ] [ assoc-size 1+ ] bi ] keep
82 swap (rehash) ; inline
84 : ?grow-hash ( hash -- )
97 : <hashtable> ( n -- hash )
98 hashtable new [ reset-hash ] keep ;
100 M: hashtable at* ( key hash -- value ? )
101 key@ [ 3 fixnum+fast slot t ] [ 2drop f f ] if ;
103 M: hashtable clear-assoc ( hash -- )
104 [ init-hash ] [ array>> [ drop ((empty)) ] change-each ] bi ;
106 M: hashtable delete-at ( key hash -- )
107 [ nip ] [ key@ ] 2bi [
108 [ ((tombstone)) dup ] 2dip set-nth-pair
114 M: hashtable assoc-size ( hash -- n )
115 [ count>> ] [ deleted>> ] bi - ;
122 M: hashtable set-at ( value key hash -- )
125 [ rot hash-count+ set-nth-pair ]
126 [ rot drop set-nth-pair ] if ;
128 : associate ( value key -- hash )
129 2 <hashtable> [ set-at ] keep ;
133 : push-unsafe ( elt seq -- )
135 [ underlying>> set-array-nth ]
136 [ [ 1 fixnum+fast { array-capacity } declare ] dip (>>length) ]
142 [ array>> [ length 2/ ] keep ] [ assoc-size <vector> ] bi [
145 [ 1 fixnum-shift-fast ] dip
146 [ array-nth ] [ [ 1 fixnum+fast ] dip array-nth ] 2bi
148 pick tombstone? [ 3drop ] [ [ 2array ] dip push-unsafe ] if
153 (clone) [ clone ] change-array ;
157 2dup [ assoc-size ] bi@ eq?
158 [ assoc= ] [ 2drop f ] if
162 M: assoc new-assoc drop <hashtable> ;
164 M: f new-assoc drop <hashtable> ;
166 : >hashtable ( assoc -- hashtable )
167 H{ } assoc-clone-like ;
169 M: hashtable assoc-like
170 drop dup hashtable? [ >hashtable ] unless ;
172 : ?set-at ( value key assoc/f -- assoc )
173 [ [ set-at ] keep ] [ associate ] if* ;
175 INSTANCE: hashtable assoc