bootstrap

view church/runtime/hashtable.state @ 867:3557dbdaf618

add new macros for getting and setting array values, which can work on both byte and word sized arrays

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