| rev |
line source |
|
jewel@802
|
1 (include "church/runtime/church_types.state")
|
|
jewel@802
|
2 (include "church/runtime/church_syntax.state")
|
|
jewel@802
|
3
|
|
jewel@802
|
4
|
|
jewel@802
|
5 (external-function |state-gc-alloc|)
|
|
jewel@833
|
6 (external-function |state-gc-alloc-and-zero|)
|
|
jewel@802
|
7 (external-function state-abort)
|
|
jewel@802
|
8 (external-function church-cons)
|
|
jewel@802
|
9
|
|
jewel@802
|
10 ; new hash table
|
|
jewel@802
|
11
|
|
jewel@802
|
12 (define church-hashtable-allocate (lambda (size)
|
|
jewel@802
|
13 (church-assert (church-> size 0) "size must be greater than 0")
|
|
jewel@802
|
14 (if (not (= (band size (- size 1)) 0))
|
|
jewel@802
|
15 (let ((highest-bit (bsr size))
|
|
jewel@802
|
16 (new-size (bshl 1 (+ highest-bit 1))))
|
|
jewel@802
|
17 ; (call-c-extern printf "given size %lu, new size %lu
|
|
jewel@802
|
18 ;" size new-size)
|
|
jewel@802
|
19 (set! size new-size) ))
|
|
jewel@802
|
20 ; size must be a power of 2
|
|
jewel@802
|
21 (church-assert (church-= (band size (- size 1)) 0) "hash table size must be a power of 2")
|
|
jewel@802
|
22 ; hash table is 8 words, plus 2 * size words
|
|
jewel@829
|
23 (let ((ht-alloc-size (+ (* 8 CHURCH_WORD_SIZE) (* size (* 2 CHURCH_WORD_SIZE))))
|
|
jewel@833
|
24 (ht (state-gc-alloc-and-zero ht-alloc-size)))
|
|
jewel@829
|
25 ; clear memory
|
|
jewel@829
|
26 (call-c-extern memset ht 0 ht-alloc-size)
|
|
jewel@829
|
27
|
|
jewel@802
|
28 (set-hashtable-size! ht size)
|
|
jewel@802
|
29 (set-hashtable-count! ht 0)
|
|
jewel@829
|
30
|
|
jewel@829
|
31
|
|
jewel@830
|
32 ; (do ((i 0 (+ i 1)))
|
|
jewel@830
|
33 ; (< i (hashtable-size ht))
|
|
jewel@830
|
34 ; (if (not (= (deref (hashtable-table ht) (* 8 i)) 0))
|
|
jewel@830
|
35 ; (begin
|
|
jewel@830
|
36 ; (call-c-extern printf "ht %p
|
|
jewel@830
|
37 ;" ht)
|
|
jewel@830
|
38 ; (state-abort "dirty hashtable"))))
|
|
jewel@830
|
39
|
|
jewel@830
|
40
|
|
jewel@802
|
41 ht)))
|
|
jewel@802
|
42
|
|
jewel@818
|
43 ;(define church-hashtable-set-functions (lambda (ht hash-fn comp-fn)
|
|
jewel@818
|
44 ; (set-hashtable-hash-function! ht hash-fn)
|
|
jewel@818
|
45 ; (set-hashtable-comp-function! ht comp-fn)
|
|
jewel@818
|
46 ; ht))
|
|
jewel@802
|
47 ;; set hash and compare function
|
|
jewel@818
|
48 (define church-hashtable-set-functions (lambda (ht hash-fn1 hash-fn2 comp-fn)
|
|
jewel@818
|
49 (set-hashtable-hash-function1! ht hash-fn1)
|
|
jewel@818
|
50 (set-hashtable-hash-function2! ht hash-fn2)
|
|
jewel@802
|
51 (set-hashtable-comp-function! ht comp-fn)
|
|
jewel@802
|
52 ht))
|
|
jewel@802
|
53
|
|
jewel@802
|
54 (define church-hashtable-has-key? (lambda (ht key)
|
|
jewel@802
|
55 (let ((hash-table (hashtable-table ht))
|
|
jewel@802
|
56 (hash-table-size (hashtable-size ht))
|
|
jewel@802
|
57 (comp-fn (hashtable-comp-function ht))
|
|
jewel@818
|
58 (h ((hashtable-hash-function1 ht) key))
|
|
jewel@818
|
59 (index (* (mod h hash-table-size) 2))
|
|
jewel@818
|
60 (probe-step ((hashtable-hash-function2 ht) key)))
|
|
jewel@802
|
61 (tagbody
|
|
jewel@802
|
62 check
|
|
jewel@818
|
63 (let ((lookup (deref hash-table (* index CHURCH_WORD_SIZE))))
|
|
jewel@802
|
64 (if (= lookup 0)
|
|
jewel@802
|
65 (return TAG_NIL)
|
|
jewel@802
|
66 )
|
|
jewel@802
|
67 (if (= (comp-fn lookup key) 0)
|
|
jewel@802
|
68 (return TAG_TRUE)
|
|
jewel@802
|
69 ))
|
|
jewel@818
|
70 (set! h (+ h probe-step))
|
|
jewel@818
|
71 ; mask out high bit
|
|
jewel@818
|
72 (set! h (band h (band -1 (bnot (bshl 1 31)))))
|
|
jewel@818
|
73 (set! index (* (mod h hash-table-size) 2))
|
|
jewel@802
|
74 (go check)))))
|
|
jewel@802
|
75
|
|
jewel@802
|
76 (define church-hashtable-lookup-key (lambda (ht key default-value)
|
|
jewel@802
|
77 (let ((hash-table (hashtable-table ht))
|
|
jewel@802
|
78 (hash-table-size (hashtable-size ht))
|
|
jewel@818
|
79 (hash-fn (hashtable-hash-function1 ht))
|
|
jewel@802
|
80 (comp-fn (hashtable-comp-function ht))
|
|
jewel@802
|
81 (h (hash-fn key))
|
|
jewel@818
|
82 (index (* (mod h hash-table-size) 2))
|
|
jewel@818
|
83 (probe-step ((hashtable-hash-function2 ht) key)))
|
|
jewel@802
|
84 (tagbody
|
|
jewel@802
|
85 check
|
|
jewel@802
|
86 ; (call-c-extern printf "find_hash_entry at index %lu
|
|
jewel@802
|
87 ;" base-index)
|
|
jewel@818
|
88 (let ((lookup (deref hash-table (* index CHURCH_WORD_SIZE))))
|
|
jewel@802
|
89 (if (= lookup 0)
|
|
jewel@802
|
90 (return default-value)
|
|
jewel@802
|
91 )
|
|
jewel@802
|
92 (if (= (comp-fn lookup key) 0)
|
|
jewel@818
|
93 (return (deref hash-table (* (+ index 1) CHURCH_WORD_SIZE)))
|
|
jewel@802
|
94 ))
|
|
jewel@818
|
95 (set! h (+ h probe-step))
|
|
jewel@818
|
96 ; mask out high bit
|
|
jewel@818
|
97 (set! h (band h (band -1 (bnot (bshl 1 31)))))
|
|
jewel@818
|
98 (set! index (* (mod h hash-table-size) 2))
|
|
jewel@802
|
99 (go check)))
|
|
jewel@802
|
100 (state-abort "failed find hash entry")))
|
|
jewel@802
|
101
|
|
jewel@802
|
102 (define church-hashtable-add-or-replace (lambda (ht key value)
|
|
jewel@829
|
103 ; (call-c-extern printf "church-hashtable-add-or-replace %p size %lu count %lu
|
|
jewel@829
|
104 ;" ht (hashtable-size ht) (hashtable-count ht))
|
|
jewel@802
|
105 (let ((new-count (church-hashtable-add-or-replace-helper ht key value)))
|
|
jewel@802
|
106 (if (> new-count 0)
|
|
jewel@802
|
107 (begin
|
|
jewel@802
|
108 (set-hashtable-count! ht (+ (hashtable-count ht) 1))
|
|
jewel@802
|
109 ; (call-c-extern printf "ht %p count %lu size %lu
|
|
jewel@802
|
110 ;" ht (hashtable-count ht) (hashtable-size ht))
|
|
jewel@802
|
111 ; check if we should grow
|
|
jewel@802
|
112 (if (> (/ (* (hashtable-count ht) 100) (hashtable-size ht)) 60)
|
|
jewel@802
|
113 (let ((newsize (* (hashtable-size ht) 2))
|
|
jewel@802
|
114 (new-ht (church-hashtable-allocate newsize)))
|
|
jewel@802
|
115 ; copy the old functions into the new table
|
|
jewel@818
|
116 (church-hashtable-set-functions new-ht (hashtable-hash-function1 ht) (hashtable-hash-function2 ht) (hashtable-comp-function ht))
|
|
jewel@802
|
117 (church-hashtable-rehash-from-old-table ht new-ht)
|
|
jewel@802
|
118 (return new-ht))
|
|
jewel@802
|
119 ht))
|
|
jewel@802
|
120 ht))))
|
|
jewel@802
|
121
|
|
jewel@802
|
122 (define church-hashtable-add-or-replace-helper (lambda (ht key value)
|
|
jewel@802
|
123 (let ((hash-table (hashtable-table ht))
|
|
jewel@802
|
124 (hash-table-size (hashtable-size ht))
|
|
jewel@818
|
125 (hash-fn (hashtable-hash-function1 ht))
|
|
jewel@802
|
126 (comp-fn (hashtable-comp-function ht))
|
|
jewel@802
|
127 (h (hash-fn key))
|
|
jewel@818
|
128 (index (* (mod h hash-table-size) 2))
|
|
jewel@818
|
129 (probe-step ((hashtable-hash-function2 ht) key)))
|
|
jewel@802
|
130 (tagbody
|
|
jewel@802
|
131 check
|
|
jewel@829
|
132 ; (call-c-extern printf "ht %p h %p index %lu, key %p value %p probe-step %p
|
|
jewel@829
|
133 ;" ht h index key value probe-step)
|
|
jewel@818
|
134 (let ((lookup (deref hash-table (* index CHURCH_WORD_SIZE))))
|
|
jewel@802
|
135 (if (= lookup 0)
|
|
jewel@802
|
136 ;add a new entry
|
|
jewel@802
|
137 (begin
|
|
jewel@818
|
138 (set-long! hash-table (* index CHURCH_WORD_SIZE) key)
|
|
jewel@818
|
139 (set-long! hash-table (* (+ index 1) CHURCH_WORD_SIZE) value)
|
|
jewel@802
|
140 (return 1))) ; 1 for new entry
|
|
jewel@802
|
141 (if (= (comp-fn lookup key) 0)
|
|
jewel@802
|
142 ; overwrite current entry
|
|
jewel@802
|
143 (begin
|
|
jewel@818
|
144 ; (call-c-extern printf "h %p index %lu at index %lu, overwrite %p %p %lu
|
|
jewel@818
|
145 ;" h index index lookup key (comp-fn lookup key))
|
|
jewel@818
|
146 (set-long! hash-table (* index CHURCH_WORD_SIZE) key)
|
|
jewel@818
|
147 (set-long! hash-table (* (+ index 1) CHURCH_WORD_SIZE) value)
|
|
jewel@802
|
148 (return 0)))) ; 0 for replacement of old entry
|
|
jewel@818
|
149 (set! h (+ h probe-step))
|
|
jewel@818
|
150 ; mask out high bit
|
|
jewel@818
|
151 (set! h (band h (band -1 (bnot (bshl 1 31)))))
|
|
jewel@818
|
152 (set! index (* (mod h hash-table-size) 2))
|
|
jewel@802
|
153 (go check)))
|
|
jewel@802
|
154 (state-abort "failed find hash entry")))
|
|
jewel@802
|
155
|
|
jewel@802
|
156 (define church-hashtable-rehash-from-old-table (lambda (ht new-ht)
|
|
jewel@802
|
157 (let ((hash-table (hashtable-table ht))
|
|
jewel@802
|
158 (hash-table-size (hashtable-size ht)))
|
|
jewel@802
|
159 (let ((counter 0)
|
|
jewel@802
|
160 (base-index 0))
|
|
jewel@802
|
161 (tagbody
|
|
jewel@802
|
162 check
|
|
jewel@802
|
163 (if (< counter hash-table-size)
|
|
jewel@802
|
164 (let ((key (deref hash-table (* base-index CHURCH_WORD_SIZE)))
|
|
jewel@802
|
165 (value (deref hash-table (* (+ base-index 1) CHURCH_WORD_SIZE))))
|
|
jewel@802
|
166 (if (not (= key 0))
|
|
jewel@802
|
167 (begin
|
|
jewel@802
|
168 (church-hashtable-add-or-replace-helper new-ht key value)
|
|
jewel@802
|
169 (set-hashtable-count! new-ht (+ (hashtable-count new-ht) 1)))
|
|
jewel@802
|
170 )
|
|
jewel@802
|
171 (set! base-index (+ base-index 2)))
|
|
jewel@802
|
172 (go end))
|
|
jewel@802
|
173 (set! counter (+ counter 1))
|
|
jewel@802
|
174 (go check)
|
|
jewel@802
|
175 end)))))
|
|
jewel@802
|
176
|
|
jewel@802
|
177 (external-function church-reverse!)
|
|
jewel@802
|
178 (define church-hashtable-keys (lambda (ht)
|
|
jewel@802
|
179 (let ((hash-table (hashtable-table ht))
|
|
jewel@802
|
180 (hash-table-size (hashtable-size ht))
|
|
jewel@802
|
181 (counter 0)
|
|
jewel@802
|
182 (base-index 0)
|
|
jewel@802
|
183 (keys TAG_NIL))
|
|
jewel@802
|
184 (tagbody
|
|
jewel@802
|
185 check
|
|
jewel@802
|
186 (if (< counter hash-table-size)
|
|
jewel@802
|
187 (let ((key (deref hash-table (* base-index CHURCH_WORD_SIZE))))
|
|
jewel@802
|
188 (if (not (= key 0))
|
|
jewel@802
|
189 (push key keys))
|
|
jewel@802
|
190 (set! base-index (+ base-index 2)))
|
|
jewel@802
|
191 (go end))
|
|
jewel@802
|
192 (set! counter (+ counter 1))
|
|
jewel@802
|
193 (go check)
|
|
jewel@802
|
194 end)
|
|
jewel@802
|
195 (church-reverse! keys))))
|
|
jewel@802
|
196
|
|
jewel@803
|
197 ; hash functions
|
|
jewel@803
|
198
|
|
jewel@803
|
199 (define church_hash_string_function (lambda (str)
|
|
jewel@803
|
200 (let ((h 0))
|
|
jewel@803
|
201 (tagbody
|
|
jewel@803
|
202 check
|
|
jewel@803
|
203 (if (= (get-byte str 0) 0)
|
|
jewel@803
|
204 (go done)
|
|
jewel@803
|
205 (begin
|
|
jewel@803
|
206 (set! h (+ (* h 31) (get-byte str 0)))
|
|
jewel@803
|
207 (set! str (+ str 1))
|
|
jewel@803
|
208 (go check)))
|
|
jewel@803
|
209 done)
|
|
jewel@803
|
210 (bshr (bshl h 1) 1) ; mask out any sign bit
|
|
jewel@803
|
211 )))
|
|
jewel@803
|
212
|
|
jewel@818
|
213 (define church_second_hash_string_function (lambda (str)
|
|
jewel@818
|
214 (let ((hash 0))
|
|
jewel@818
|
215 (tagbody
|
|
jewel@818
|
216 check
|
|
jewel@818
|
217 (if (= (get-byte str 0) 0)
|
|
jewel@818
|
218 (go done)
|
|
jewel@818
|
219 (begin
|
|
jewel@818
|
220 (set! hash (+ hash (get-byte str 0)))
|
|
jewel@818
|
221 (set! hash (+ hash (bshl hash 10)))
|
|
jewel@818
|
222 (set! hash (bxor hash (bshr hash 6)))
|
|
jewel@818
|
223 (set! str (+ str 1))
|
|
jewel@818
|
224 ))
|
|
jewel@818
|
225 done)
|
|
jewel@818
|
226 (set! hash (+ hash (bshl hash 3)))
|
|
jewel@818
|
227 (set! hash (bxor hash (bshr hash 11)))
|
|
jewel@818
|
228 (set! hash (+ hash (bshl hash 15)))
|
|
jewel@818
|
229 ; our result must always be odd to be relatively prime to the size of table (multiple of 2)
|
|
jewel@818
|
230 (bor
|
|
jewel@818
|
231 (bshr (bshl hash 1) 1) ; mask out any sign bit
|
|
jewel@818
|
232 1))))
|
|
jewel@818
|
233
|
|
jewel@803
|
234 (define church_compare_string_function (lambda (a b)
|
|
jewel@803
|
235 ; (call-c-extern printf "comparing strings %p %p '%s' '%s'
|
|
jewel@803
|
236 ;" a b a b)
|
|
jewel@803
|
237 (call-c-extern strcmp a b)))
|
|
jewel@803
|
238
|
|
jewel@818
|
239 (define church_default_hash_function (lambda (key1)
|
|
jewel@818
|
240 (let ((p 16777619)
|
|
jewel@818
|
241 (h 2166136261))
|
|
jewel@818
|
242 ; unroll 4 times for each byte in the key
|
|
jewel@818
|
243 (set! h (* p (bxor h (band key1 #xff))))
|
|
jewel@818
|
244 (set! key1 (bshr key1 8))
|
|
jewel@818
|
245 (set! h (* p (bxor h (band key1 #xff))))
|
|
jewel@818
|
246 (set! key1 (bshr key1 8))
|
|
jewel@818
|
247 (set! h (* p (bxor h (band key1 #xff))))
|
|
jewel@818
|
248 (set! key1 (bshr key1 8))
|
|
jewel@818
|
249 (set! h (* p (bxor h (band key1 #xff))))
|
|
jewel@818
|
250
|
|
jewel@818
|
251 (set! h (+ h (bshl h 13)))
|
|
jewel@818
|
252 (set! h (bxor h (bshr h 7)))
|
|
jewel@818
|
253 (set! h (+ h (bshl h 3)))
|
|
jewel@818
|
254 (set! h (bxor h (bshr h 17)))
|
|
jewel@818
|
255 (set! h (+ h (bshl h 5)))
|
|
jewel@818
|
256 (band h (band -1 (bnot (bshl 1 31))))
|
|
jewel@818
|
257 )))
|
|
jewel@818
|
258
|
|
jewel@818
|
259
|
|
jewel@818
|
260 (define church_default_second_hash_function (lambda (key1)
|
|
jewel@818
|
261 (let ((hash 0))
|
|
jewel@818
|
262 (do ((i 0 (+ i 1)))
|
|
jewel@818
|
263 (< i 4)
|
|
jewel@818
|
264 (set! hash (+ hash (band key1 #xff)))
|
|
jewel@818
|
265 (set! hash (+ hash (bshl hash 10)))
|
|
jewel@818
|
266 (set! hash (bxor hash (bshr hash 6)))
|
|
jewel@818
|
267 (set! key1 (bshr key1 8))
|
|
jewel@818
|
268 )
|
|
jewel@818
|
269 (set! hash (+ hash (bshl hash 3)))
|
|
jewel@818
|
270 (set! hash (bxor hash (bshr hash 11)))
|
|
jewel@818
|
271 (set! hash (+ hash (bshl hash 15)))
|
|
jewel@818
|
272 ; our result must always be odd to be relatively prime to the size of table (multiple of 2)
|
|
jewel@818
|
273 (bor
|
|
jewel@818
|
274 (band hash (band -1 (bnot (bshl 1 31))))
|
|
jewel@818
|
275 1))))
|
|
jewel@818
|
276
|
|
jewel@803
|
277 (define church_default_compare_function (lambda (a b)
|
|
jewel@818
|
278 (- a b)))
|
|
jewel@803
|
279
|
|
jewel@803
|
280 (external-function church_profiled_apply1)
|
|
jewel@803
|
281 (external-function church_profiled_apply2)
|
|
jewel@803
|
282 (external-function state-init-constant)
|
|
jewel@803
|
283 (external-function state-alloc-constant-vector)
|
|
jewel@803
|
284
|
|
jewel@803
|
285 (define church_equal_hash_function (lambda (obj)
|
|
jewel@803
|
286 (apply 'hash obj)))
|
|
jewel@803
|
287 (define church_equal_compare_function (lambda (a b)
|
|
jewel@803
|
288 (let ((result (apply 'equal? a b)))
|
|
jewel@803
|
289 (if (= result TAG_TRUE)
|
|
jewel@803
|
290 0
|
|
jewel@803
|
291 (- b a)))))
|
|
jewel@803
|
292
|
|
jewel@815
|
293
|
|
jewel@815
|
294 ; two key hashtable
|
|
jewel@815
|
295
|
|
jewel@815
|
296 ; new hash table
|
|
jewel@815
|
297
|
|
jewel@815
|
298 (define church-two-key-hashtable-allocate (lambda (size)
|
|
jewel@815
|
299 (church-assert (church-> size 0) "size must be greater than 0")
|
|
jewel@815
|
300 (if (not (= (band size (- size 1)) 0))
|
|
jewel@815
|
301 (let ((highest-bit (bsr size))
|
|
jewel@815
|
302 (new-size (bshl 1 (+ highest-bit 1))))
|
|
jewel@820
|
303 ; (call-c-extern printf "church-two-key-hashtable-allocate given size %lu, new size %lu
|
|
jewel@820
|
304 ;" size new-size)
|
|
jewel@815
|
305 (set! size new-size)))
|
|
jewel@815
|
306 ; size must be a power of 2
|
|
jewel@815
|
307 (church-assert (church-= (band size (- size 1)) 0) "hash table size must be a power of 2")
|
|
jewel@815
|
308 ; hash table is 8 words, plus 4 * size words
|
|
jewel@835
|
309 (let ((ht-alloc-size (+ (* 8 CHURCH_WORD_SIZE) (* size (* 4 CHURCH_WORD_SIZE))))
|
|
jewel@835
|
310 (ht (state-gc-alloc-and-zero ht-alloc-size)))
|
|
jewel@816
|
311 (if (= ht 0)
|
|
jewel@835
|
312 (state-abort "hash table alloc failed"))
|
|
jewel@835
|
313 ; clear memory
|
|
jewel@835
|
314 (call-c-extern memset ht 0 ht-alloc-size)
|
|
jewel@815
|
315 (set-hashtable-size! ht size)
|
|
jewel@815
|
316 (set-hashtable-count! ht 0)
|
|
jewel@817
|
317 ; 0 probes
|
|
jewel@820
|
318 ; (set-long! ht (* 7 CHURCH_WORD_SIZE) 0)
|
|
jewel@815
|
319 ht)))
|
|
jewel@815
|
320
|
|
jewel@820
|
321 ;(define church-two-key-hashtable-print-stats (lambda (ht)
|
|
jewel@820
|
322 ; (call-c-extern printf "two hash-table count %lu probes %lu, avg probes %lu
|
|
jewel@820
|
323 ;" (hashtable-count ht) (deref ht (* 7 CHURCH_WORD_SIZE)) (/ (deref ht (* 7 CHURCH_WORD_SIZE)) (hashtable-count ht) ))))
|
|
jewel@817
|
324
|
|
jewel@815
|
325
|
|
jewel@815
|
326 (define church-two-key-hashtable-has-keys? (lambda (ht key1 key2)
|
|
jewel@818
|
327 (state-abort "has keys")
|
|
jewel@815
|
328 (let ((hash-table (hashtable-table ht))
|
|
jewel@815
|
329 (hash-table-size (hashtable-size ht))
|
|
jewel@815
|
330 (hash-fn (hashtable-hash-function ht))
|
|
jewel@815
|
331 (comp-fn (hashtable-comp-function ht))
|
|
jewel@815
|
332 (h (bor (hash-fn key1) (hash-fn key2)))
|
|
jewel@815
|
333 (index (mod h hash-table-size))
|
|
jewel@815
|
334 ; align to 4 word boundary
|
|
jewel@815
|
335 (base-index (band (* index 4) -4))
|
|
jewel@815
|
336 (orig-index base-index))
|
|
jewel@815
|
337 (tagbody
|
|
jewel@815
|
338 check
|
|
jewel@815
|
339 (let ((lookup1 (deref hash-table (* base-index CHURCH_WORD_SIZE)))
|
|
jewel@815
|
340 (lookup2 (deref hash-table (* (+ base-index 1) CHURCH_WORD_SIZE))))
|
|
jewel@815
|
341 (if (and (= lookup1 0)
|
|
jewel@815
|
342 (= lookup2 0))
|
|
jewel@815
|
343 (return TAG_NIL))
|
|
jewel@815
|
344 (if (and (= (comp-fn lookup1 key1) 0)
|
|
jewel@815
|
345 (= (comp-fn lookup2 key2) 0))
|
|
jewel@815
|
346 (return TAG_TRUE)))
|
|
jewel@815
|
347 (set! base-index (+ base-index 4))
|
|
jewel@815
|
348 ; check if we have wrappend around the top of the table
|
|
jewel@815
|
349 (if (= base-index (* hash-table-size 4))
|
|
jewel@815
|
350 (set! base-index 0))
|
|
jewel@815
|
351 (go check)))))
|
|
jewel@815
|
352
|
|
jewel@815
|
353 ; return a pointer to the result
|
|
jewel@815
|
354 ; 0 if not found
|
|
jewel@815
|
355 (define church-two-key-hashtable-lookup-keys (lambda (ht key1 key2)
|
|
jewel@815
|
356 (let ((hash-table (hashtable-table ht))
|
|
jewel@815
|
357 (hash-table-size (hashtable-size ht))
|
|
jewel@817
|
358 (h (church-two-key-hash-function key1 key2))
|
|
jewel@817
|
359 (index (* (mod h hash-table-size) 4))
|
|
jewel@817
|
360 (probe-step (church-two-key-second-hash-function key1 key2)))
|
|
jewel@815
|
361 (tagbody
|
|
jewel@815
|
362 check
|
|
jewel@816
|
363 ; note that the first key cannot be a fixnum
|
|
jewel@817
|
364 (let ((l1 (deref hash-table (* index CHURCH_WORD_SIZE)) 0))
|
|
jewel@816
|
365 (if (= l1 0)
|
|
jewel@815
|
366 (return 0))
|
|
jewel@816
|
367 (if (= l1 key1)
|
|
jewel@817
|
368 (if (= (deref hash-table (* (+ index 1) CHURCH_WORD_SIZE)) key2)
|
|
jewel@817
|
369 (return (+ hash-table (* (+ index 2) CHURCH_WORD_SIZE))))))
|
|
jewel@817
|
370 (set! h (+ h probe-step))
|
|
jewel@817
|
371 ; mask out high bit
|
|
jewel@817
|
372 (set! h (band h (band -1 (bnot (bshl 1 31)))))
|
|
jewel@818
|
373 (set! index (* (mod h hash-table-size) 4))
|
|
jewel@815
|
374 (go check)))
|
|
jewel@815
|
375 (state-abort "failed find hash entry")))
|
|
jewel@815
|
376
|
|
jewel@815
|
377
|
|
jewel@815
|
378 (define church-two-key-hashtable-add-or-replace (lambda (ht key1 key2 value1 value2)
|
|
jewel@815
|
379 (let ((new-count (church-two-key-hashtable-add-or-replace-helper ht key1 key2 value1 value2)))
|
|
jewel@815
|
380 (if (> new-count 0)
|
|
jewel@815
|
381 (begin
|
|
jewel@815
|
382 (set-hashtable-count! ht (+ (hashtable-count ht) 1))
|
|
jewel@815
|
383 ; (call-c-extern printf "after add two-key ht %p count %lu size %lu
|
|
jewel@815
|
384 ;" ht (hashtable-count ht) (hashtable-size ht))
|
|
jewel@815
|
385 ; check if we should grow
|
|
jewel@815
|
386 (if (> (/ (* (hashtable-count ht) 100) (hashtable-size ht)) 60)
|
|
jewel@815
|
387 (let ((newsize (* (hashtable-size ht) 2))
|
|
jewel@815
|
388 (new-ht (church-two-key-hashtable-allocate newsize)))
|
|
jewel@818
|
389 ;(call-c-extern printf "growing two key ht %p count %lu size %lu
|
|
jewel@818
|
390 ;" ht (hashtable-count ht) newsize)
|
|
jewel@815
|
391 ; copy the old functions into the new table
|
|
jewel@818
|
392 (church-hashtable-set-functions new-ht (hashtable-hash-function1 ht) (hashtable-hash-function2 ht) (hashtable-comp-function ht))
|
|
jewel@815
|
393 (church-two-key-hashtable-rehash-from-old-table ht new-ht)
|
|
jewel@815
|
394 (return new-ht))
|
|
jewel@815
|
395 ht))
|
|
jewel@815
|
396 ht))))
|
|
jewel@815
|
397
|
|
jewel@815
|
398 (define church-two-key-hashtable-add-or-replace-helper (lambda (ht key1 key2 value1 value2)
|
|
jewel@815
|
399 (let ((hash-table (hashtable-table ht))
|
|
jewel@815
|
400 (hash-table-size (hashtable-size ht))
|
|
jewel@815
|
401 (h (church-two-key-hash-function key1 key2))
|
|
jewel@817
|
402 (index (* (mod h hash-table-size) 4))
|
|
jewel@817
|
403 (probe-step (church-two-key-second-hash-function key1 key2)))
|
|
jewel@817
|
404 ; (call-c-extern printf "add key1 %p key2 %p, h %p index %lu at index %lu (%p)
|
|
jewel@817
|
405 ;" key1 key2 h index index index)
|
|
jewel@815
|
406 (tagbody
|
|
jewel@815
|
407 check
|
|
jewel@817
|
408
|
|
jewel@817
|
409 (let ((l1 (deref hash-table (* index CHURCH_WORD_SIZE)) 0))
|
|
jewel@816
|
410 (if (= l1 0)
|
|
jewel@817
|
411 (if (= (deref hash-table (* (+ index 1) CHURCH_WORD_SIZE)) 0)
|
|
jewel@816
|
412 (begin
|
|
jewel@817
|
413 (set-long! hash-table (* index CHURCH_WORD_SIZE) key1)
|
|
jewel@817
|
414 (set-long! hash-table (* (+ index 1) CHURCH_WORD_SIZE) key2)
|
|
jewel@817
|
415 (set-long! hash-table (* (+ index 2) CHURCH_WORD_SIZE) value1)
|
|
jewel@817
|
416 (set-long! hash-table (* (+ index 3) CHURCH_WORD_SIZE) value2)
|
|
jewel@816
|
417 (return 1) ; new entry
|
|
jewel@816
|
418 )))
|
|
jewel@816
|
419 (if (= l1 key1)
|
|
jewel@817
|
420 (if (= (deref hash-table (* (+ index 1) CHURCH_WORD_SIZE)) key2)
|
|
jewel@816
|
421 (begin
|
|
jewel@817
|
422 (set-long! hash-table (* index CHURCH_WORD_SIZE) key1)
|
|
jewel@817
|
423 (set-long! hash-table (* (+ index 1) CHURCH_WORD_SIZE) key2)
|
|
jewel@817
|
424 (set-long! hash-table (* (+ index 2) CHURCH_WORD_SIZE) value1)
|
|
jewel@817
|
425 (set-long! hash-table (* (+ index 3) CHURCH_WORD_SIZE) value2)
|
|
jewel@839
|
426 (return 0) ; existing entry
|
|
jewel@817
|
427 ))))
|
|
jewel@817
|
428 ; (call-c-extern printf "add key1 %p key2 %p, h %p index %lu at index %lu (%p) PROBING
|
|
jewel@817
|
429 ;" key1 key2 h index index index)
|
|
jewel@817
|
430 ; count the number of probes
|
|
jewel@817
|
431 ; (set-long! ht (* 7 CHURCH_WORD_SIZE) (+ 1 (deref ht (* 7 CHURCH_WORD_SIZE))))
|
|
jewel@817
|
432 (set! h (+ h probe-step))
|
|
jewel@817
|
433 ; mask out high bit
|
|
jewel@817
|
434 (set! h (band h (band -1 (bnot (bshl 1 31)))))
|
|
jewel@817
|
435 (set! index (mod h hash-table-size))
|
|
jewel@815
|
436 (go check)))
|
|
jewel@815
|
437 (state-abort "failed find hash entry")))
|
|
jewel@815
|
438
|
|
jewel@815
|
439 (define church-two-key-hashtable-rehash-from-old-table (lambda (ht new-ht)
|
|
jewel@815
|
440 (let ((hash-table (hashtable-table ht))
|
|
jewel@815
|
441 (hash-table-size (hashtable-size ht)))
|
|
jewel@815
|
442 (let ((counter 0)
|
|
jewel@815
|
443 (base-index 0))
|
|
jewel@815
|
444 (tagbody
|
|
jewel@815
|
445 check
|
|
jewel@815
|
446 (if (< counter hash-table-size)
|
|
jewel@815
|
447 (let ((key1 (deref hash-table (* base-index CHURCH_WORD_SIZE)))
|
|
jewel@815
|
448 (key2 (deref hash-table (* (+ base-index 1) CHURCH_WORD_SIZE)))
|
|
jewel@815
|
449 (value1 (deref hash-table (* (+ base-index 2) CHURCH_WORD_SIZE) ))
|
|
jewel@815
|
450 (value2 (deref hash-table (* (+ base-index 3) CHURCH_WORD_SIZE) )) (value1 (deref hash-table (* (+ base-index 2) CHURCH_WORD_SIZE) )))
|
|
jewel@815
|
451 (if (not (and (= key1 0)
|
|
jewel@815
|
452 (= key2 0)))
|
|
jewel@815
|
453 (begin
|
|
jewel@815
|
454 (church-two-key-hashtable-add-or-replace-helper new-ht key1 key2 value1 value2)
|
|
jewel@815
|
455 (set-hashtable-count! new-ht (+ (hashtable-count new-ht) 1)))
|
|
jewel@815
|
456 )
|
|
jewel@815
|
457 (set! base-index (+ base-index 4)))
|
|
jewel@815
|
458 (go end))
|
|
jewel@815
|
459 (set! counter (+ counter 1))
|
|
jewel@815
|
460 (go check)
|
|
jewel@815
|
461 end)))))
|
|
jewel@816
|
462
|
|
jewel@819
|
463 ; Modified FNV from Pluto Scarab, http://home.comcast.net/~bretm/hash/6.html
|
|
jewel@819
|
464
|
|
jewel@816
|
465 (define church-two-key-hash-function (lambda (key1 key2)
|
|
jewel@816
|
466 (let ((p 16777619)
|
|
jewel@816
|
467 (h 2166136261))
|
|
jewel@816
|
468 (do ((i 0 (+ i 1)))
|
|
jewel@816
|
469 (< i 4)
|
|
jewel@816
|
470 (set! h (* p (bxor h (band key1 #xff))))
|
|
jewel@817
|
471 ; (call-c-extern printf "hash1 %p key1 %p
|
|
jewel@817
|
472 ;" h key1)
|
|
jewel@817
|
473 (set! key1 (bshr key1 8)))
|
|
jewel@816
|
474 (do ((i 0 (+ i 1)))
|
|
jewel@816
|
475 (< i 4)
|
|
jewel@816
|
476 (set! h (* p (bxor h (band key2 #xff))))
|
|
jewel@817
|
477 ; (call-c-extern printf "hash1 %p key2 %p
|
|
jewel@817
|
478 ;" h key2)
|
|
jewel@817
|
479 (set! key2 (bshr key2 8)))
|
|
jewel@816
|
480 (set! h (+ h (bshl h 13)))
|
|
jewel@816
|
481 (set! h (bxor h (bshr h 7)))
|
|
jewel@816
|
482 (set! h (+ h (bshl h 3)))
|
|
jewel@816
|
483 (set! h (bxor h (bshr h 17)))
|
|
jewel@816
|
484 (set! h (+ h (bshl h 5)))
|
|
jewel@816
|
485 (band h (band -1 (bnot (bshl 1 31)))) )))
|
|
jewel@816
|
486
|
|
jewel@817
|
487
|
|
jewel@819
|
488 ; Jenkins hash function from wikipedia / dr. dobbs
|
|
jewel@819
|
489
|
|
jewel@817
|
490 (define church-two-key-second-hash-function (lambda (key1 key2)
|
|
jewel@817
|
491 (let ((hash 0))
|
|
jewel@817
|
492 (do ((i 0 (+ i 1)))
|
|
jewel@817
|
493 (< i 4)
|
|
jewel@817
|
494 (set! hash (+ hash (band key1 #xff)))
|
|
jewel@817
|
495 (set! hash (+ hash (bshl hash 10)))
|
|
jewel@817
|
496 (set! hash (bxor hash (bshr hash 6)))
|
|
jewel@817
|
497 (set! key1 (bshr key1 8))
|
|
jewel@817
|
498 )
|
|
jewel@817
|
499 (do ((i 0 (+ i 1)))
|
|
jewel@817
|
500 (< i 4)
|
|
jewel@817
|
501 (set! hash (+ hash (band key2 #xff)))
|
|
jewel@817
|
502 (set! hash (+ hash (bshl hash 10)))
|
|
jewel@817
|
503 (set! hash (bxor hash (bshr hash 6)))
|
|
jewel@817
|
504 (set! key2 (bshr key1 8))
|
|
jewel@817
|
505 )
|
|
jewel@817
|
506 (set! hash (+ hash (bshl hash 3)))
|
|
jewel@817
|
507 (set! hash (bxor hash (bshr hash 11)))
|
|
jewel@817
|
508 (set! hash (+ hash (bshl hash 15)))
|
|
jewel@817
|
509 ; our result must always be odd to be relatively prime to the size of table (multiple of 2)
|
|
jewel@817
|
510 (bor
|
|
jewel@817
|
511 (band hash (band -1 (bnot (bshl 1 31))))
|
|
jewel@817
|
512 1))))
|
|
jewel@817
|
513
|
|
jewel@817
|
514
|