1;;; hash.ms
2;;; Copyright 1984-2017 Cisco Systems, Inc.
3;;;
4;;; Licensed under the Apache License, Version 2.0 (the "License");
5;;; you may not use this file except in compliance with the License.
6;;; You may obtain a copy of the License at
7;;;
8;;; http://www.apache.org/licenses/LICENSE-2.0
9;;;
10;;; Unless required by applicable law or agreed to in writing, software
11;;; distributed under the License is distributed on an "AS IS" BASIS,
12;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13;;; See the License for the specific language governing permissions and
14;;; limitations under the License.
15
16(mat old-hash-table
17  (error? (get-hash-table '((a . b)) 'a #f))
18  (error? (put-hash-table! (list (cons 'a 'b)) 'a 'b))
19  (error? (remove-hash-table! (list (cons 'a 'b)) 'a))
20  (error? (hash-table-map '((a . b)) cons))
21  (error? (hash-table-for-each '((a . b)) cons))
22  (begin
23    (define $h-ht (make-hash-table))
24    (hash-table? $h-ht))
25  (not (hash-table? 3))
26  (not (hash-table? '$h-ht))
27  (null? (hash-table-map $h-ht list))
28  (eq? (let ([n 0])
29         (hash-table-for-each $h-ht (lambda (x y) (set! n (+ n 1))))
30         n)
31       0)
32  (equal?
33    (begin
34      (put-hash-table! $h-ht 'ham 'spam)
35      (hash-table-map $h-ht list))
36    '((ham spam)))
37  (error? ; wrong number of args
38    (hash-table-map $h-ht (lambda (x) x)))
39  (error? ; wrong number of args
40    (hash-table-for-each $h-ht (lambda (x) x)))
41  ((lambda (x y) (or (equal? x y) (equal? x (reverse y))))
42    (begin
43      (put-hash-table! $h-ht 'cram 'sham)
44      (hash-table-map $h-ht list))
45    '((ham spam) (cram sham)))
46  ((lambda (x y) (or (equal? x y) (equal? x (reverse y))))
47    (begin
48      (put-hash-table! $h-ht 'ham 'jam)
49      (hash-table-map $h-ht list))
50    '((ham jam) (cram sham)))
51  (eq? (get-hash-table $h-ht 'ham #f) 'jam)
52  (eq? (get-hash-table $h-ht 'cram #f) 'sham)
53  (eq? (get-hash-table $h-ht 'sham #f) #f)
54  (equal? (get-hash-table $h-ht 'jam "rats") "rats")
55  (eq? (let ([n 0])
56         (hash-table-for-each $h-ht (lambda (x y) (set! n (+ n 1))))
57         n)
58       2)
59  ((lambda (x y) (or (equal? x y) (equal? x (reverse y))))
60   (let ([keys '()] [vals '()])
61     (hash-table-for-each $h-ht
62       (lambda (k v)
63         (set! keys (cons k keys))
64         (set! vals (cons v vals))))
65     (map cons vals keys))
66   '((jam . ham) (sham . cram)))
67  (eq? (collect (collect-maximum-generation)) (void))
68  ((lambda (x y) (or (equal? x y) (equal? x (reverse y))))
69   (let ([keys '()] [vals '()])
70     (hash-table-for-each $h-ht
71       (lambda (k v)
72         (set! keys (cons k keys))
73         (set! vals (cons v vals))))
74     (map cons vals keys))
75   '((jam . ham) (sham . cram)))
76  (eq? (begin
77         (remove-hash-table! $h-ht 'ham)
78         (get-hash-table $h-ht 'ham 'gone!))
79       'gone!)
80  (equal?
81    (hash-table-map $h-ht list)
82    '((cram sham)))
83  (eq? (collect (collect-maximum-generation)) (void))
84  (equal?
85    (hash-table-map $h-ht list)
86    '((cram sham)))
87  (eq? (begin
88         (remove-hash-table! $h-ht 'ham)
89         (get-hash-table $h-ht 'ham 'gone!))
90       'gone!)
91  (equal?
92    (hash-table-map $h-ht list)
93    '((cram sham)))
94  (eq? (begin
95         (remove-hash-table! $h-ht 'sham)
96         (get-hash-table $h-ht 'ham 'never-there!))
97       'never-there!)
98  (equal?
99    (hash-table-map $h-ht list)
100    '((cram sham)))
101  (eq? (begin
102         (remove-hash-table! $h-ht 'cram)
103         (get-hash-table $h-ht 'cram 'gone-too!))
104       'gone-too!)
105  (null? (hash-table-map $h-ht list))
106
107 ; fasling out eq hash tables
108  (equal?
109    (let ([x (cons 'y '!)])
110      (define ht (make-hash-table))
111      (put-hash-table! ht x 'because)
112      (put-hash-table! ht 'foo "foo")
113      (let ([p (open-file-output-port "testfile.ss" (file-options replace))])
114        (fasl-write (list x ht) p)
115        (close-port p))
116      (let-values ([(x2 ht2)
117                    (apply values
118                      (call-with-port
119                        (open-file-input-port "testfile.ss")
120                        fasl-read))])
121        (list
122          (get-hash-table ht2 x2 #f)
123          (get-hash-table ht2 'foo #f))))
124    '(because "foo"))
125
126 ; weak hash table tests
127  (begin
128    (define $h-ht (make-hash-table #t))
129    (hash-table? $h-ht))
130  (null?
131    (begin
132      (put-hash-table! $h-ht (string #\a) 'yea!)
133      (collect (collect-maximum-generation))
134      (hash-table-map $h-ht cons)))
135  (eq? (let ([n 0])
136         (hash-table-for-each $h-ht (lambda (x y) (set! n (+ n 1))))
137         n)
138       0)
139  (let ([s (string #\a)])
140    (put-hash-table! $h-ht s 666)
141    (equal? (get-hash-table $h-ht s #f) 666))
142  (null?
143    (begin
144      (collect (collect-maximum-generation))
145      (hash-table-map $h-ht cons)))
146
147 ; make sure that nonweak hash tables are nonweak (explicit #f arg)
148  (begin
149    (define $h-ht (make-hash-table #f))
150    (hash-table? $h-ht))
151  (equal?
152    (begin
153      (put-hash-table! $h-ht (string #\a) "bc")
154      (collect (collect-maximum-generation))
155      (hash-table-map $h-ht string-append))
156    '("abc"))
157
158 ; make sure that nonweak hash tables are nonweak (implicit #f arg)
159  (begin
160    (define $h-ht (make-hash-table))
161    (hash-table? $h-ht))
162  (equal?
163    (begin
164      (put-hash-table! $h-ht (string #\a) "bc")
165      (collect (collect-maximum-generation))
166      (hash-table-map $h-ht string-append))
167    '("abc"))
168
169 ; stress tests
170  (let () ; nonweak
171    (define pick
172      (lambda (ls)
173        (list-ref ls (random (length ls)))))
174    (define ht (make-hash-table))
175    (let* ([ls (remq '|| (oblist))] [n 50000])
176      (let f ([i 0] [keep '()] [drop '()])
177        (if (= i n)
178            (and (= (length (hash-table-map ht (lambda (x y) x)))
179                    (- n (length drop)))
180                 (andmap (lambda (k)
181                           (string=?
182                             (symbol->string (get-hash-table ht k #f))
183                             (cond
184                               [(string? k) k]
185                               [(pair? k) (car k)]
186                               [(vector? k) (vector-ref k 0)])))
187                         keep)
188                 (andmap (lambda (k) (eq? (get-hash-table ht k 'no) 'no))
189                         drop))
190            (let* ([x (pick ls)] [s (string-copy (symbol->string x))])
191              (let ([k (case (pick '(string pair vector))
192                         [(string) s]
193                         [(pair) (list s)]
194                         [(vector) (vector s)])])
195                (put-hash-table! ht k x)
196                (let ([keep (if (= (modulo i 5) 0) (cons k keep) keep)])
197                  (if (= (modulo i 17) 5)
198                      (let ([k (pick keep)])
199                        (remove-hash-table! ht k)
200                        (let ([drop (cons k drop)])
201                          (when (= (random 5) 3)
202                            (remove-hash-table! ht (pick drop)))
203                          (f (+ i 1) (remq k keep) drop)))
204                      (f (+ i 1) keep drop)))))))))
205
206  (let () ; weak
207    (define pick
208      (lambda (ls)
209        (list-ref ls (random (length ls)))))
210    (define ht (make-hash-table #t))
211    (let* ([ls (remq '|| (oblist))] [n 50000])
212      (let f ([i 0] [keep '()] [drop '()])
213        (if (= i n)
214            (and (<= (length (hash-table-map ht (lambda (x y) x)))
215                     (- n (length drop)))
216                 (begin
217                   (collect (collect-maximum-generation))
218                   (= (length (hash-table-map ht (lambda (x y) x)))
219                      (length keep)))
220                 (andmap (lambda (k)
221                           (string=?
222                             (symbol->string (get-hash-table ht k #f))
223                             (cond
224                               [(string? k) k]
225                               [(pair? k) (car k)]
226                               [(vector? k) (vector-ref k 0)])))
227                         keep)
228                 (andmap (lambda (k) (eq? (get-hash-table ht k 'no) 'no))
229                         drop))
230            (let* ([x (pick ls)] [s (string-copy (symbol->string x))])
231              (let ([k (case (pick '(string pair vector))
232                         [(string) s]
233                         [(pair) (list s)]
234                         [(vector) (vector s)])])
235                (put-hash-table! ht k x)
236                (let ([keep (if (= (modulo i 5) 0) (cons k keep) keep)])
237                  (if (= (modulo i 17) 5)
238                      (let ([k (pick keep)])
239                        (remove-hash-table! ht k)
240                        (let ([drop (cons k drop)])
241                          (when (= (random 5) 3)
242                            (remove-hash-table! ht (pick drop)))
243                          (f (+ i 1) (remq k keep) drop)))
244                      (f (+ i 1) keep drop)))))))))
245)
246
247(mat tlc
248  (critical-section
249    (let ()
250      (define ht (make-eq-hashtable))
251      (define keyval '(a . b))
252      (define next 0)
253      (define tlc (#%$make-tlc ht keyval next))
254      (define tlc2 (#%$make-tlc ht keyval next))
255      (and
256        (#%$tlc? tlc)
257        (not (#%$tlc? keyval))
258        (eq? (#%$tlc-ht tlc) ht)
259        (eq? (#%$tlc-keyval tlc) keyval)
260        (eqv? (#%$tlc-next tlc) next)
261        (begin
262          (#%$set-tlc-next! tlc tlc2)
263          (eq? (#%$tlc-next tlc) tlc2)))))
264)
265
266(define $vector-andmap
267  (lambda (p . v*)
268    (apply andmap p (map vector->list v*))))
269
270(define $vector-append
271  (lambda v*
272    (list->vector (apply append (map vector->list v*)))))
273
274(define $vector-member?
275  (lambda (x v)
276    (let ([n (vector-length v)])
277      (let f ([i 0])
278        (and (not (fx= i n))
279          (or (equal? (vector-ref v i) x)
280              (f (fx+ i 1))))))))
281
282(define same-elements?
283  (lambda (v1 v2)
284    (let ([n (vector-length v1)])
285      (define (each-in? v1 v2)
286        (let f ([i 0])
287          (or (fx= i n)
288              (and ($vector-member? (vector-ref v1 i) v2)
289                   (f (fx+ i 1))))))
290      (and (fx= (vector-length v2) n)
291           (each-in? v1 v2)
292           (each-in? v2 v1)))))
293
294(define equal-entries?
295  (lambda (ht keys vals)
296    (define-syntax same-entries?
297      (syntax-rules ()
298        [(_ e1 keys2 vals2)
299         (let-values ([(keys1 vals1) e1])
300           (and
301            (same-elements? keys1 keys2)
302            (same-elements? vals1 vals2)))]))
303
304    (and
305     (same-elements? (hashtable-keys ht) keys)
306     (same-elements? (hashtable-values ht) vals)
307     (same-entries? (hashtable-entries ht) keys vals)
308     (same-elements? (hashtable-cells ht) (vector-map cons keys vals))
309
310     (same-elements? (r6rs:hashtable-keys ht) keys)
311     (same-entries? (r6rs:hashtable-entries ht) keys vals)
312
313     ;; Check requested sizes > hash table size
314     (andmap (lambda (size)
315               (and
316                (same-elements? (hashtable-keys ht size) keys)
317                (same-elements? (hashtable-values ht size) vals)
318                (same-entries? (hashtable-entries ht size) keys vals)
319                (same-elements? (hashtable-cells ht size) (vector-map cons keys vals))))
320             (list (add1 (hashtable-size ht))
321                   (expt 2 1000)))
322
323     ;; Make sure request of 0 always works:
324     (same-elements? (hashtable-keys ht 0) '#())
325     (same-elements? (hashtable-values ht 0) '#())
326     (same-entries? (hashtable-entries ht 0) '#() '#())
327     (same-elements? (hashtable-cells ht 0) '#())
328
329     (or
330      (< (hashtable-size ht) 2)
331      ;; Check request of size 2:
332      (let ([twos (lambda (v)
333                     (let i-loop ([i 0])
334                       (cond
335                        [(= i (vector-length v))
336                         '()]
337                        [else
338                         (let j-loop ([j (add1 i)])
339                           (cond
340                            [(= j (vector-length v))
341                             (i-loop (add1 i))]
342                            [else
343                             (cons (vector (vector-ref v i) (vector-ref v j))
344                                   (j-loop (add1 j)))]))])))])
345        (let ([keyss (twos keys)]
346              [valss (twos vals)])
347          (and
348           (let ([got-keys (hashtable-keys ht 2)])
349             (ormap (lambda (keys)
350                      (same-elements? got-keys keys))
351                    keyss))
352           (let ([got-vals (hashtable-values ht 2)])
353             (ormap (lambda (vals)
354                      (same-elements? got-vals vals))
355                    valss))
356           (let-values ([(got-keys got-vals) (hashtable-entries ht 2)])
357             (ormap (lambda (keys vals)
358                      (and (same-elements? got-keys keys)
359                           (same-elements? got-vals vals)))
360                    keyss valss))
361           (let ([got-cells (hashtable-cells ht 2)])
362             (ormap (lambda (keys vals)
363                      (same-elements? got-cells (vector-map cons keys vals)))
364                    keyss valss)))))))))
365
366(mat hashtable-arguments
367 ; make-eq-hashtable
368  (error? ; wrong argument count
369    (make-eq-hashtable 3 #t))
370  (error? ; invalid size
371    (make-eq-hashtable -1))
372  (error? ; invalid size
373    (make-eq-hashtable #t))
374  (error? ; invalid size
375    (make-eq-hashtable #f))
376 ; make-hashtable
377  (error? ; wrong argument count
378    (make-hashtable))
379  (error? ; wrong argument count
380    (make-hashtable equal-hash))
381  (error? ; wrong argument count
382    (make-hashtable equal-hash equal? 45 53))
383  (error? ; not a procedure
384    (make-hashtable 'a equal? 45))
385  (error? ; not a procedure
386    (make-hashtable equal-hash 'a 45))
387  (error? ; invalid size
388    (make-hashtable equal-hash equal? 'a))
389  (error? ; invalid size
390    (make-hashtable equal-hash equal? -45))
391  (error? ; invalid size
392    (make-hashtable equal-hash equal? 45.0))
393 ; make-eqv-hashtable
394  (error? ; wrong argument count
395    (make-eqv-hashtable 3 #t))
396  (error? ; invalid size
397    (make-eqv-hashtable -1))
398  (error? ; invalid size
399    (make-eqv-hashtable #t))
400  (error? ; invalid size
401    (make-eqv-hashtable #f))
402  (begin
403    (define $ht (make-eq-hashtable))
404    (define $imht (hashtable-copy $ht))
405    (define $ht2 (make-eq-hashtable 50))
406    (and (hashtable? $ht)
407         (eq-hashtable? $ht)
408         (hashtable-mutable? $ht)
409         (not (hashtable-weak? $ht))
410         (not (eq-hashtable-weak? $ht))
411         (not (hashtable-ephemeron? $ht))
412         (not (eq-hashtable-ephemeron? $ht))
413         (hashtable? $imht)
414         (eq-hashtable? $imht)
415         (not (hashtable-mutable? $imht))
416         (not (hashtable-weak? $imht))
417         (not (eq-hashtable-weak? $imht))
418         (not (hashtable-ephemeron? $imht))
419         (not (eq-hashtable-ephemeron? $imht))
420         (hashtable? $ht2)
421         (eq-hashtable? $ht2)
422         (hashtable-mutable? $ht2)
423         (not (hashtable-weak? $ht2))
424         (not (eq-hashtable-weak? $ht2))
425         (not (hashtable-ephemeron? $ht2))
426         (not (eq-hashtable-ephemeron? $ht2))))
427  (not (hashtable? 3))
428  (not (hashtable? (make-vector 3)))
429  (not (eq-hashtable? 3))
430  (not (eq-hashtable? (make-vector 3)))
431 ; hashtable?
432  (error? ; wrong argument count
433    (hashtable?))
434  (error? ; wrong argument count
435    (hashtable? $ht 3))
436  (error? ; wrong argument count
437    (eq-hashtable?))
438  (error? ; wrong argument count
439    (eq-hashtable? $ht 3))
440 ; hashtable-mutable?
441  (error? ; not a hashtable
442    (hashtable-mutable? (make-vector 3)))
443  (error? ; wrong argument count
444    (hashtable-mutable?))
445  (error? ; wrong argument count
446    (hashtable-mutable? $ht 3))
447 ; hashtable-size
448  (error? ; wrong argument count
449    (hashtable-size))
450  (error? ; wrong argument count
451    (hashtable-size $ht 3))
452  (error? ; not a hashtable
453    (hashtable-size 'hello))
454 ; hashtable-ref
455  (error? ; wrong argument count
456    (hashtable-ref))
457  (error? ; wrong argument count
458    (hashtable-ref $ht))
459  (error? ; wrong argument count
460    (hashtable-ref $ht 'a))
461  (error? ; wrong argument count
462    (hashtable-ref $ht 'a 'b 'c))
463  (error? ; not a hashtable
464    (hashtable-ref '(hash . table) 'a 'b))
465 ; hashtable-contains?
466  (error? ; wrong argument count
467    (hashtable-contains?))
468  (error? ; wrong argument count
469    (hashtable-contains? $ht))
470  (error? ; wrong argument count
471    (hashtable-contains? $ht 'a 'b))
472  (error? ; not a hashtable
473    (hashtable-contains? '(hash . table) 'a))
474 ; hashtable-set!
475  (error? ; wrong argument count
476    (hashtable-set!))
477  (error? ; wrong argument count
478    (hashtable-set! $ht))
479  (error? ; wrong argument count
480    (hashtable-set! $ht 'a))
481  (error? ; wrong argument count
482    (hashtable-set! $ht 'a 'b 'c))
483  (error? ; not a hashtable
484    (hashtable-set! '(hash . table) 'a 'b))
485  (error? ; hashtable not mutable
486    (hashtable-set! $imht 'a 'b))
487 ; hashtable-update!
488  (error? ; wrong argument count
489    (hashtable-update!))
490  (error? ; wrong argument count
491    (hashtable-update! $ht))
492  (error? ; wrong argument count
493    (hashtable-update! $ht 'a values))
494  (error? ; wrong argument count
495    (hashtable-update! $ht 'a values 'c 'd))
496  (error? ; not a hashtable
497    (hashtable-update! '(hash . table) 'a values 'b))
498  (error? ; hashtable not mutable
499    (hashtable-update! $imht 'a values 'b))
500  (error? ; not a procedure
501    (hashtable-update! $ht 'a "not a procedure" 'b))
502 ; hashtable-cell
503  (error? ; wrong argument count
504    (hashtable-cell))
505  (error? ; wrong argument count
506    (hashtable-cell $ht))
507  (error? ; wrong argument count
508    (hashtable-cell $ht 'a))
509  (error? ; wrong argument count
510    (hashtable-cell $ht 'a 'b 'c))
511  (error? ; not a hashtable
512    (hashtable-cell '(hash . table) 'a 'b))
513 ; hashtable-delete!
514  (error? ; wrong argument count
515    (hashtable-delete!))
516  (error? ; wrong argument count
517    (hashtable-delete! $ht))
518  (error? ; wrong argument count
519    (hashtable-delete! $ht 'a 'b))
520  (error? ; not a hashtable
521    (hashtable-delete! '(hash . table) 'a))
522  (error? ; hashtable not mutable
523    (hashtable-delete! $imht 'a))
524 ; hashtable-copy
525  (error? ; wrong argument count
526    (hashtable-copy))
527  (error? ; wrong argument count
528    (hashtable-copy $ht #t 17))
529  (error? ; not a hashtable
530    (hashtable-copy '(hash . table) #t))
531 ; hashtable-clear!
532  (error? ; wrong argument count
533    (hashtable-clear!))
534  (error? ; wrong argument count
535    (hashtable-clear! $ht 17 'foo))
536  (error? ; not a hashtable
537    (hashtable-clear! '(hash . table)))
538  (error? ; not a hashtable
539    (hashtable-clear! '(hash . table) 17))
540  (error? ; hashtable not mutable
541    (hashtable-clear! $imht))
542  (error? ; hashtable not mutable
543    (hashtable-clear! $imht 32))
544  (error? ; invalid size
545    (hashtable-clear! $ht #t))
546 ; hashtable-keys
547  (error? ; wrong argument count
548    (hashtable-keys))
549  (error? ; wrong argument count
550    (hashtable-keys $ht 72 43))
551  (error? ; not a hashtable
552    (hashtable-keys '(hash . table)))
553  (error? ; bad size
554    (hashtable-keys $ht -79))
555  (error? ; bad size
556    (hashtable-keys $ht 'not-an-unsigned-integer))
557  (error? ; wrong argument count
558    (r6rs:hashtable-keys))
559  (error? ; wrong argument count
560    (r6rs:hashtable-keys $ht 72))
561  (error? ; not a hashtable
562    (r6rs:hashtable-keys '(hash . table)))
563 ; hashtable-values
564  (error? ; wrong argument count
565    (hashtable-values))
566  (error? ; wrong argument count
567    (hashtable-values $ht 72 43))
568  (error? ; not a hashtable
569    (hashtable-values '(hash . table)))
570  (error? ; bad size
571    (hashtable-values $ht -79))
572  (error? ; bad size
573    (hashtable-values $ht 'not-an-unsigned-integer))
574 ; hashtable-entries
575  (error? ; wrong argument count
576    (hashtable-entries))
577  (error? ; wrong argument count
578    (hashtable-entries $ht 72 43))
579  (error? ; not a hashtable
580    (hashtable-entries '(hash . table)))
581  (error? ; bad size
582    (hashtable-entries $ht -79))
583  (error? ; bad size
584    (hashtable-entries $ht 'not-an-unsigned-integer))
585  (error? ; wrong argument count
586    (r6rs:hashtable-entries))
587  (error? ; wrong argument count
588    (r6rs:hashtable-entries $ht 72))
589  (error? ; not a hashtable
590    (r6rs:hashtable-entries '(hash . table)))
591 ; hashtable-cells
592  (error? ; wrong argument count
593    (hashtable-cells))
594  (error? ; wrong argument count
595    (hashtable-cells $ht 72 43))
596  (error? ; not a hashtable
597    (hashtable-cells '(hash . table)))
598  (error? ; bad size
599    (hashtable-cells $ht -79))
600  (error? ; bad size
601    (hashtable-cells $ht 'not-an-unsigned-integer))
602 ; hashtable-hash-function
603  (error? ; wrong argument count
604    (hashtable-hash-function))
605  (error? ; wrong argument count
606    (hashtable-hash-function $ht $ht))
607  (error? ; not a hsshtable
608    (hashtable-hash-function '(hash . table)))
609 ; hashtable-equivalence-function
610  (error? ; wrong argument count
611    (hashtable-equivalence-function))
612  (error? ; wrong argument count
613    (hashtable-equivalence-function $ht $ht))
614  (error? ; not a hsshtable
615    (hashtable-equivalence-function '(hash . table)))
616 ; hashtable-weak?
617  (error? ; wrong argument count
618    (hashtable-weak?))
619  (error? ; wrong argument count
620    (hashtable-weak? $ht 3))
621  (error? ; not a hashtable
622    (hashtable-weak? '(hash . table)))
623 ; hashtable-ephemeron?
624  (error? ; wrong argument count
625    (hashtable-ephemeron?))
626  (error? ; wrong argument count
627    (hashtable-ephemeron? $ht 3))
628  (error? ; not a hashtable
629    (hashtable-ephemeron? '(hash . table)))
630)
631
632(mat hash-return-value
633  ; hashtable-ref
634  (error? ; invalid hash-function return value
635    (let ([ht (make-hashtable (lambda (x) "oops") equal?)])
636      (hashtable-ref ht 'any #f)))
637  #;(error? ; invalid hash-function return value
638    (let ([ht (make-hashtable (lambda (x) -7) equal?)])
639      (hashtable-ref ht 'any #f)))
640  (error? ; invalid hash-function return value
641    (let ([ht (make-hashtable (lambda (x) 3.5) equal?)])
642      (hashtable-ref ht 'any #f)))
643  (error? ; invalid hash-function return value
644    (let ([ht (make-hashtable (lambda (x) 1+2i) equal?)])
645      (hashtable-ref ht 'any #f)))
646  ; hashtable-contains?
647  (error? ; invalid hash-function return value
648    (let ([ht (make-hashtable (lambda (x) "oops") equal?)])
649      (hashtable-contains? ht 'any)))
650  #;(error? ; invalid hash-function return value
651    (let ([ht (make-hashtable (lambda (x) -7) equal?)])
652      (hashtable-contains? ht 'any)))
653  (error? ; invalid hash-function return value
654    (let ([ht (make-hashtable (lambda (x) 3.5) equal?)])
655      (hashtable-contains? ht 'any)))
656  (error? ; invalid hash-function return value
657    (let ([ht (make-hashtable (lambda (x) 1+2i) equal?)])
658      (hashtable-contains? ht 'any)))
659  ; hashtable-set!
660  (error? ; invalid hash-function return value
661    (let ([ht (make-hashtable (lambda (x) "oops") equal?)])
662      (hashtable-set! ht 'any 'spam)))
663  #;(error? ; invalid hash-function return value
664    (let ([ht (make-hashtable (lambda (x) -7) equal?)])
665      (hashtable-set! ht 'any 'spam)))
666  (error? ; invalid hash-function return value
667    (let ([ht (make-hashtable (lambda (x) 3.5) equal?)])
668      (hashtable-set! ht 'any 'spam)))
669  (error? ; invalid hash-function return value
670    (let ([ht (make-hashtable (lambda (x) 1+2i) equal?)])
671      (hashtable-set! ht 'any 'spam)))
672  ; hashtable-update!
673  (error? ; invalid hash-function return value
674    (let ([ht (make-hashtable (lambda (x) "oops") equal?)])
675      (hashtable-update! ht 'any values 'spam)))
676  #;(error? ; invalid hash-function return value
677    (let ([ht (make-hashtable (lambda (x) -7) equal?)])
678      (hashtable-update! ht 'any values 'spam)))
679  (error? ; invalid hash-function return value
680    (let ([ht (make-hashtable (lambda (x) 3.5) equal?)])
681      (hashtable-update! ht 'any values 'spam)))
682  (error? ; invalid hash-function return value
683    (let ([ht (make-hashtable (lambda (x) 1+2i) equal?)])
684      (hashtable-update! ht 'any values 'spam)))
685  ; hashtable-cell
686  (error? ; invalid hash-function return value
687    (let ([ht (make-hashtable (lambda (x) "oops") equal?)])
688      (hashtable-cell ht 'any 0)))
689  #;(error? ; invalid hash-function return value
690    (let ([ht (make-hashtable (lambda (x) -7) equal?)])
691      (hashtable-cell ht 'any 0)))
692  (error? ; invalid hash-function return value
693    (let ([ht (make-hashtable (lambda (x) 3.5) equal?)])
694      (hashtable-cell ht 'any 0)))
695  (error? ; invalid hash-function return value
696    (let ([ht (make-hashtable (lambda (x) 1+2i) equal?)])
697      (hashtable-cell ht 'any 0)))
698  ; hashtable-delete!
699  (error? ; invalid hash-function return value
700    (let ([ht (make-hashtable (lambda (x) "oops") equal?)])
701      (hashtable-delete! ht 'any)))
702  #;(error? ; invalid hash-function return value
703    (let ([ht (make-hashtable (lambda (x) -7) equal?)])
704      (hashtable-delete! ht 'any)))
705  (error? ; invalid hash-function return value
706    (let ([ht (make-hashtable (lambda (x) 3.5) equal?)])
707      (hashtable-delete! ht 'any)))
708  (error? ; invalid hash-function return value
709    (let ([ht (make-hashtable (lambda (x) 1+2i) equal?)])
710      (hashtable-delete! ht 'any)))
711)
712
713(mat eq-hashtable-arguments
714 ; make-weak-eq-hashtable
715  (error? ; wrong argument count
716    (make-weak-eq-hashtable 3 #t))
717  (error? ; invalid size
718    (make-weak-eq-hashtable -1))
719  (error? ; invalid size
720    (make-weak-eq-hashtable #t))
721  (error? ; invalid size
722    (make-weak-eq-hashtable #f))
723 ; make-weak-eq-hashtable
724  (error? ; wrong argument count
725    (make-ephemeron-eq-hashtable 3 #t))
726  (error? ; invalid size
727    (make-ephemeron-eq-hashtable -1))
728  (error? ; invalid size
729    (make-ephemeron-eq-hashtable #t))
730  (error? ; invalid size
731    (make-ephemeron-eq-hashtable #f))
732  (begin
733    (define $wht (make-weak-eq-hashtable 50))
734    (define $eht (make-ephemeron-eq-hashtable 50))
735    (define $imht (hashtable-copy $wht))
736    (define $imeht (hashtable-copy $eht))
737    (define $wht2 (make-weak-eq-hashtable))
738    (define $eht2 (make-ephemeron-eq-hashtable))
739    (and (hashtable? $wht)
740         (hashtable? $eht)
741         (eq-hashtable? $wht)
742         (eq-hashtable? $eht)
743         (hashtable-weak? $wht)
744         (not (hashtable-ephemeron? $wht))
745         (hashtable-ephemeron? $eht)
746         (not (hashtable-weak? $eht))
747         (eq-hashtable-weak? $wht)
748         (not (eq-hashtable-ephemeron? $wht))
749         (eq-hashtable-ephemeron? $eht)
750         (not (eq-hashtable-weak? $eht))
751         (hashtable-mutable? $wht)
752         (hashtable-mutable? $eht)
753         (hashtable? $imht)
754         (hashtable? $imeht)
755         (eq-hashtable? $imht)
756         (eq-hashtable? $imeht)
757         (hashtable-weak? $imht)
758         (not (hashtable-ephemeron? $imht))
759         (hashtable-ephemeron? $imeht)
760         (not (hashtable-weak? $imeht))
761         (eq-hashtable-weak? $imht)
762         (not (eq-hashtable-ephemeron? $imht))
763         (eq-hashtable-ephemeron? $imeht)
764         (not (eq-hashtable-weak? $imeht))
765         (not (hashtable-mutable? $imht))
766         (not (hashtable-mutable? $imeht))
767         (hashtable? $wht2)
768         (hashtable? $eht2)
769         (eq-hashtable? $wht2)
770         (eq-hashtable? $eht2)
771         (hashtable-weak? $wht2)
772         (not (hashtable-ephemeron? $wht2))
773         (hashtable-ephemeron? $eht2)
774         (not (hashtable-weak? $eht2))
775         (eq-hashtable-weak? $wht2)
776         (not (eq-hashtable-ephemeron? $ht2))
777         (eq-hashtable-ephemeron? $eht2)
778         (not (eq-hashtable-weak? $eht2))
779         (hashtable-mutable? $wht2)
780         (hashtable-mutable? $eht2)))
781 ; eq-hashtable-ref
782  (error? ; wrong argument count
783    (eq-hashtable-ref))
784  (error? ; wrong argument count
785    (eq-hashtable-ref $wht))
786  (error? ; wrong argument count
787    (eq-hashtable-ref $wht 'a))
788  (error? ; wrong argument count
789    (eq-hashtable-ref $wht 'a 'b 'c))
790  (error? ; not a hashtable
791    (eq-hashtable-ref '(hash . table) 'a 'b))
792 ; eq-hashtable-contains?
793  (error? ; wrong argument count
794    (eq-hashtable-contains?))
795  (error? ; wrong argument count
796    (eq-hashtable-contains? $wht))
797  (error? ; wrong argument count
798    (eq-hashtable-contains? $wht 'a 'b))
799  (error? ; not a hashtable
800    (eq-hashtable-contains? '(hash . table) 'a))
801 ; eq-hashtable-set!
802  (error? ; wrong argument count
803    (eq-hashtable-set!))
804  (error? ; wrong argument count
805    (eq-hashtable-set! $wht))
806  (error? ; wrong argument count
807    (eq-hashtable-set! $wht 'a))
808  (error? ; wrong argument count
809    (eq-hashtable-set! $wht 'a 'b 'c))
810  (error? ; not a hashtable
811    (eq-hashtable-set! '(hash . table) 'a 'b))
812  (error? ; hashtable not mutable
813    (eq-hashtable-set! $imht 'a 'b))
814 ; eq-hashtable-update!
815  (error? ; wrong argument count
816    (eq-hashtable-update!))
817  (error? ; wrong argument count
818    (eq-hashtable-update! $wht))
819  (error? ; wrong argument count
820    (eq-hashtable-update! $wht 'a values))
821  (error? ; wrong argument count
822    (eq-hashtable-update! $wht 'a values 'c 'd))
823  (error? ; not a hashtable
824    (eq-hashtable-update! '(hash . table) 'a values 'b))
825  (error? ; hashtable not mutable
826    (eq-hashtable-update! $imht 'a values 'b))
827  (error? ; not a procedure
828    (eq-hashtable-update! $wht 'a "not a procedure" 'b))
829 ; eq-hashtable-delete!
830  (error? ; wrong argument count
831    (eq-hashtable-delete!))
832  (error? ; wrong argument count
833    (eq-hashtable-delete! $wht))
834  (error? ; wrong argument count
835    (eq-hashtable-delete! $wht 'a 'b))
836  (error? ; not a hashtable
837    (eq-hashtable-delete! '(hash . table) 'a))
838  (error? ; hashtable not mutable
839    (eq-hashtable-delete! $imht 'a))
840 ; eq-hashtable-cell
841  (error? ; wrong argument count
842    (eq-hashtable-cell))
843  (error? ; wrong argument count
844    (eq-hashtable-cell $wht))
845  (error? ; wrong argument count
846    (eq-hashtable-cell $wht 'a))
847  (error? ; wrong argument count
848    (eq-hashtable-cell $wht 'a 'b 'c))
849  (error? ; not a hashtable
850    (eq-hashtable-cell '(hash . table) 'a 'b))
851 ; eq-hashtable-weak?
852  (error? ; wrong argument count
853    (eq-hashtable-weak?))
854  (error? ; wrong argument count
855    (eq-hashtable-weak? $ht 3))
856  (error? ; not a hashtable
857    (eq-hashtable-weak? '(hash . table)))
858 ; eq-hashtable-ephemeron?
859  (error? ; wrong argument count
860    (eq-hashtable-ephemeron?))
861  (error? ; wrong argument count
862    (eq-hashtable-ephemeron? $ht 3))
863  (error? ; not a hashtable
864    (eq-hashtable-ephemeron? '(hash . table)))
865)
866
867(mat symbol-hashtable-arguments
868  (begin
869    (define $symht (make-hashtable symbol-hash eq? 50))
870    (define $imsymht (hashtable-copy $symht))
871    #t)
872 ; symbol-hashtable-ref
873  (error? ; wrong argument count
874    (symbol-hashtable-ref))
875  (error? ; wrong argument count
876    (symbol-hashtable-ref $symht))
877  (error? ; wrong argument count
878    (symbol-hashtable-ref $symht 'a))
879  (error? ; wrong argument count
880    (symbol-hashtable-ref $symht 'a 'b 'c))
881  (error? ; not a hashtable
882    (symbol-hashtable-ref '(hash . table) 'a 'b))
883  (error? ; not a symbol hashtable
884    (symbol-hashtable-ref $ht 'a 'b))
885  (error? ; not a symbol
886    (symbol-hashtable-ref $symht '(a) 'b))
887  (error? ; not a symbol
888    (hashtable-ref $symht '(a) 'b))
889 ; symbol-hashtable-contains?
890  (error? ; wrong argument count
891    (symbol-hashtable-contains?))
892  (error? ; wrong argument count
893    (symbol-hashtable-contains? $symht))
894  (error? ; wrong argument count
895    (symbol-hashtable-contains? $symht 'a 'b))
896  (error? ; not a hashtable
897    (symbol-hashtable-contains? '(hash . table) 'a))
898  (error? ; not a symbol hashtable
899    (symbol-hashtable-contains? $ht 'a))
900  (error? ; not a symbol
901    (symbol-hashtable-contains? $symht '(a)))
902  (error? ; not a symbol
903    (hashtable-contains? $symht '(a)))
904 ; symbol-hashtable-set!
905  (error? ; wrong argument count
906    (symbol-hashtable-set!))
907  (error? ; wrong argument count
908    (symbol-hashtable-set! $symht))
909  (error? ; wrong argument count
910    (symbol-hashtable-set! $symht 'a))
911  (error? ; wrong argument count
912    (symbol-hashtable-set! $symht 'a 'b 'c))
913  (error? ; not a hashtable
914    (symbol-hashtable-set! '(hash . table) 'a 'b))
915  (error? ; not a symbol hashtable
916    (symbol-hashtable-set! $ht 'a 'b))
917  (error? ; not a symbol
918    (symbol-hashtable-set! $symht '(a) 'b))
919  (error? ; not a symbol
920    (hashtable-set! $symht '(a) 'b))
921  (error? ; hashtable not mutable
922    (symbol-hashtable-set! $imsymht 'a 'b))
923 ; symbol-hashtable-update!
924  (error? ; wrong argument count
925    (symbol-hashtable-update!))
926  (error? ; wrong argument count
927    (symbol-hashtable-update! $symht))
928  (error? ; wrong argument count
929    (symbol-hashtable-update! $symht 'a values))
930  (error? ; wrong argument count
931    (symbol-hashtable-update! $symht 'a values 'c 'd))
932  (error? ; not a hashtable
933    (symbol-hashtable-update! '(hash . table) 'a values 'b))
934  (error? ; not a symbol hashtable
935    (symbol-hashtable-update! $ht 'a values 'b))
936  (error? ; not a symbol
937    (symbol-hashtable-update! $symht '(a) values 'b))
938  (error? ; not a symbol
939    (hashtable-update! $symht '(a) values 'b))
940  (error? ; hashtable not mutable
941    (symbol-hashtable-update! $imsymht 'a values 'b))
942  (error? ; not a procedure
943    (symbol-hashtable-update! $symht 'a "not a procedure" 'b))
944 ; symbol-hashtable-delete!
945  (error? ; wrong argument count
946    (symbol-hashtable-delete!))
947  (error? ; wrong argument count
948    (symbol-hashtable-delete! $symht))
949  (error? ; wrong argument count
950    (symbol-hashtable-delete! $symht 'a 'b))
951  (error? ; not a hashtable
952    (symbol-hashtable-delete! '(hash . table) 'a))
953  (error? ; not a symbol hashtable
954    (symbol-hashtable-delete! $ht 'a))
955  (error? ; not a symbol
956    (symbol-hashtable-delete! $symht '(a)))
957  (error? ; not a symbol
958    (hashtable-delete! $symht '(a)))
959  (error? ; hashtable not mutable
960    (symbol-hashtable-delete! $imsymht 'a))
961 ; symbol-hashtable-cell
962  (error? ; wrong argument count
963    (symbol-hashtable-cell))
964  (error? ; wrong argument count
965    (symbol-hashtable-cell $symht))
966  (error? ; wrong argument count
967    (symbol-hashtable-cell $symht 'a))
968  (error? ; wrong argument count
969    (symbol-hashtable-cell $symht 'a 'b 'c))
970  (error? ; not a hashtable
971    (symbol-hashtable-cell '(hash . table) 'a 'b))
972  (error? ; not a symbol hashtable
973    (symbol-hashtable-cell $ht 'a 'b))
974  (error? ; not a symbol
975    (symbol-hashtable-cell $symht '(a) 'b))
976  (error? ; not a symbol
977    (hashtable-cell $symht '(a) 'b))
978)
979
980(mat eqv-hashtable-arguments
981 ; make-weak-eqv-hashtable
982  (error? ; wrong argument count
983    (make-weak-eqv-hashtable 3 #t))
984  (error? ; invalid size
985    (make-weak-eqv-hashtable -1))
986  (error? ; invalid size
987    (make-weak-eqv-hashtable #t))
988  (error? ; invalid size
989    (make-weak-eqv-hashtable #f))
990 ; make-ephemeron-eqv-hashtable
991  (error? ; wrong argument count
992    (make-ephemeron-eqv-hashtable 3 #t))
993  (error? ; invalid size
994    (make-ephemeron-eqv-hashtable -1))
995  (error? ; invalid size
996    (make-ephemeron-eqv-hashtable #t))
997  (error? ; invalid size
998    (make-ephemeron-eqv-hashtable #f))
999)
1000
1001(mat nonweak-eq-hashtable
1002  (begin
1003    (define h (make-eq-hashtable 32))
1004    (and (hashtable? h)
1005         (eq-hashtable? h)
1006         (hashtable-mutable? h)
1007         (not (eq-hashtable-weak? h))
1008         (not (eq-hashtable-ephemeron? h))
1009         (not (hashtable-weak? h))
1010         (not (hashtable-ephemeron? h))))
1011  (eq? (hashtable-hash-function h) #f)
1012  (eq? (hashtable-equivalence-function h) eq?)
1013  (equal? (hashtable-size h) 0)
1014  (equal-entries? h '#() '#())
1015  (eqv? (hashtable-set! h 'a 'aval) (void))
1016  (equal?
1017    (list
1018       (hashtable-contains? h 'a)
1019       (hashtable-contains? h 'b)
1020       (hashtable-contains? h 'c))
1021    '(#t #f #f))
1022  (eqv? (hashtable-set! h 'b 'bval) (void))
1023  (equal?
1024    (list
1025       (hashtable-contains? h 'a)
1026       (hashtable-contains? h 'b)
1027       (hashtable-contains? h 'c))
1028    '(#t #t #f))
1029  (eqv? (hashtable-set! h 'c 'cval) (void))
1030  (equal?
1031    (list
1032       (hashtable-contains? h 'a)
1033       (hashtable-contains? h 'b)
1034       (hashtable-contains? h 'c))
1035    '(#t #t #t))
1036  (equal? (hashtable-size h) 3)
1037  (equal-entries? h '#(b c a) '#(bval cval aval))
1038  #;(same-elements? (list->vector (hashtable-map h cons)) '#((a . aval) (b . bval) (c . cval)))
1039  #;(same-elements?
1040    (let ([v (make-vector 3)] [i 0])
1041      (hashtable-for-each h (lambda (key val) (vector-set! v i (cons key val)) (set! i (fx+ i 1))))
1042      v)
1043    '#((a . aval) (b . bval) (c . cval)))
1044  #;(same-elements?
1045    (let ([v (make-vector 3)] [i 0])
1046      (hashtable-for-each-cell h (lambda (a) (vector-set! v i a) (set! i (fx+ i 1))))
1047      v)
1048    '#((a . aval) (b . bval) (c . cval)))
1049  (equal? (hashtable-ref h 'a 1) 'aval)
1050  (equal? (hashtable-ref h 'b #f) 'bval)
1051  (equal? (hashtable-ref h 'c 'nope) 'cval)
1052  (eqv? (hashtable-delete! h 'b) (void))
1053  (equal? (hashtable-size h) 2)
1054  (equal-entries? h '#(a c) '#(aval cval))
1055  (begin
1056    (define h2 (hashtable-copy h #t))
1057    (and (hashtable? h2)
1058         (eq-hashtable? h2)
1059         (hashtable-mutable? h2)
1060         (not (hashtable-weak? h2))
1061         (not (eq-hashtable-weak? h2))
1062         (not (hashtable-ephemeron? h2))
1063         (not (eq-hashtable-ephemeron? h2))))
1064  (eq? (hashtable-hash-function h2) #f)
1065  (eq? (hashtable-equivalence-function h2) eq?)
1066  (equal? (hashtable-size h2) 2)
1067  (equal-entries? h2 '#(a c) '#(aval cval))
1068  (eqv? (hashtable-clear! h 4) (void))
1069  (equal?
1070    (list
1071      (hashtable-size h)
1072      (hashtable-ref h 'a 1)
1073      (hashtable-ref h 'b #f)
1074      (hashtable-ref h 'c 'nope))
1075   '(0 1 #f nope))
1076  (equal-entries? h '#() '#())
1077  (equal?
1078    (list
1079      (hashtable-size h2)
1080      (hashtable-ref h2 'a 1)
1081      (hashtable-ref h2 'b #f)
1082      (hashtable-ref h2 'c 'nope))
1083    '(2 aval #f cval))
1084  (equal-entries? h2 '#(a c) '#(aval cval))
1085  (eqv?
1086    (hashtable-update! h 'q
1087      (lambda (x) (+ x 1))
1088      17)
1089    (void))
1090  (equal? (hashtable-ref h 'q #f) 18)
1091  (eqv?
1092    (hashtable-update! h 'q
1093      (lambda (x) (+ x 1))
1094      17)
1095    (void))
1096  (equal? (hashtable-ref h 'q #f) 19)
1097  (equal? (hashtable-size h) 1)
1098 ; test hashtable-copy when some keys may have moved
1099  (let ([t (parameterize ([collect-request-handler void])
1100             (let ([h4a (make-eq-hashtable 32)]
1101                   [k* (map list (make-list 100))])
1102               (for-each (lambda (x) (hashtable-set! h4a x x)) k*)
1103               (collect)
1104              ; create copy after collection but before otherwise touching h4a
1105               (let ([h4b (hashtable-copy h4a #t)])
1106                 (andmap
1107                   (lambda (k) (eq? (hashtable-ref h4b k #f) k))
1108                   k*))))])
1109    (collect)
1110    t)
1111
1112 ; test for proper shrinkage
1113  (eqv?
1114    (let ([ht (make-eq-hashtable 32)])
1115      (for-each
1116        (lambda (k*) (for-each (lambda (k) (hashtable-delete! ht k)) k*))
1117        (let ([k** (map (lambda (x) (map list (make-list 1000)))
1118                        (make-list 100))])
1119          (for-each
1120            (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*))
1121            k**)
1122          k**))
1123      (#%$hashtable-veclen ht))
1124    32)
1125)
1126
1127(mat weak-eq-hashtable
1128  (begin
1129    (define ka (list 'a))
1130    (define kb (list 'b))
1131    (define kc (list 'c))
1132    (define kq (list 'q))
1133    (define ky (list 'y))
1134    (define kz (list 'z))
1135    #t)
1136  (begin
1137    (define h (make-weak-eq-hashtable 32))
1138    (and (hashtable? h)
1139         (eq-hashtable? h)
1140         (hashtable-mutable? h)
1141         (hashtable-weak? h)
1142         (eq-hashtable-weak? h)))
1143  (eq? (hashtable-hash-function h) #f)
1144  (eq? (hashtable-equivalence-function h) eq?)
1145  (equal? (hashtable-size h) 0)
1146  (equal-entries? h '#() '#())
1147  (eqv? (hashtable-set! h ka 'aval) (void))
1148  (equal?
1149    (list
1150       (hashtable-contains? h ka)
1151       (hashtable-contains? h kb)
1152       (hashtable-contains? h kc))
1153    '(#t #f #f))
1154  (eqv? (hashtable-set! h kb 'bval) (void))
1155  (equal?
1156    (list
1157       (hashtable-contains? h ka)
1158       (hashtable-contains? h kb)
1159       (hashtable-contains? h kc))
1160    '(#t #t #f))
1161  (eqv? (hashtable-set! h kc 'cval) (void))
1162  (equal?
1163    (list
1164       (hashtable-contains? h ka)
1165       (hashtable-contains? h kb)
1166       (hashtable-contains? h kc))
1167    '(#t #t #t))
1168  (equal? (hashtable-size h) 3)
1169  (equal-entries? h '#((a) (b) (c)) '#(aval bval cval))
1170  (andmap weak-pair? (vector->list (hashtable-cells h)))
1171  #;(same-elements? (list->vector (hashtable-map h cons)) '#(((a) . aval) ((b) . bval) ((c) . cval)))
1172  #;(same-elements?
1173    (let ([v (make-vector 3)] [i 0])
1174      (hashtable-for-each h (lambda (key val) (vector-set! v i (cons key val)) (set! i (fx+ i 1))))
1175      v)
1176    '#(((a) . aval) ((b) . bval) ((c) . cval)))
1177  #;(same-elements?
1178    (let ([v (make-vector 3)] [i 0])
1179      (hashtable-for-each-cell h (lambda (a) (vector-set! v i a) (set! i (fx+ i 1))))
1180      v)
1181    '#(((a) . aval) ((b) . bval) ((c) . cval)))
1182  (equal? (hashtable-ref h ka 1) 'aval)
1183  (equal? (hashtable-ref h kb #f) 'bval)
1184  (equal? (hashtable-ref h kc 'nope) 'cval)
1185  (eqv? (hashtable-delete! h kb) (void))
1186  (equal? (hashtable-size h) 2)
1187  (equal-entries? h '#((a) (c)) '#(aval cval))
1188  (begin
1189    (define h2 (hashtable-copy h #t))
1190    (and (hashtable? h2)
1191         (eq-hashtable? h2)
1192         (hashtable-mutable? h2)
1193         (eq-hashtable-weak? h2)
1194         (hashtable-weak? h2)))
1195  (eq? (hashtable-hash-function h2) #f)
1196  (eq? (hashtable-equivalence-function h2) eq?)
1197  (equal? (hashtable-size h2) 2)
1198  (equal-entries? h2 '#((a) (c)) '#(aval cval))
1199  (eqv? (hashtable-clear! h 4) (void))
1200  (equal?
1201    (list
1202      (hashtable-size h)
1203      (hashtable-ref h ka 1)
1204      (hashtable-ref h kb #f)
1205      (hashtable-ref h kc 'nope))
1206   '(0 1 #f nope))
1207  (equal-entries? h '#() '#())
1208  (equal?
1209    (list
1210      (hashtable-size h2)
1211      (hashtable-ref h2 ka 1)
1212      (hashtable-ref h2 kb #f)
1213      (hashtable-ref h2 kc 'nope))
1214    '(2 aval #f cval))
1215  (equal-entries? h2 '#((a) (c)) '#(aval cval))
1216  (eqv?
1217    (hashtable-update! h kq
1218      (lambda (x) (+ x 1))
1219      17)
1220    (void))
1221  (equal? (hashtable-ref h kq #f) 18)
1222  (eqv?
1223    (hashtable-update! h kq
1224      (lambda (x) (+ x 1))
1225      17)
1226    (void))
1227  (equal? (hashtable-ref h kq #f) 19)
1228  (equal? (hashtable-size h) 1)
1229  (equal-entries? h '#((q)) '#(19))
1230  (eqv?
1231    (begin
1232      (set! kq (void))
1233      (collect (collect-maximum-generation))
1234      (hashtable-size h))
1235    0)
1236  (equal-entries? h '#() '#())
1237  #;(eqv? (hashtable-map h (lambda args (error #f "oops"))) '())
1238  #;(eqv? (hashtable-for-each h (lambda args (error #f "oops"))) (void))
1239  #;(eqv? (hashtable-for-each-cell h (lambda args (error #f "oops"))) (void))
1240  (equal? (hashtable-ref h ky #f) #f)
1241  (eqv?
1242    (hashtable-set! h ky 'toad)
1243    (void))
1244  (equal? (hashtable-ref h ky #f) 'toad)
1245  (equal? (hashtable-ref h kz #f) #f)
1246  (eqv?
1247    (hashtable-update! h kz list 'frog)
1248    (void))
1249  (equal? (hashtable-ref h kz #f) '(frog))
1250  (equal-entries?
1251    h
1252    (vector kz ky)
1253    (vector (hashtable-ref h kz #f) 'toad))
1254  (eqv? (hashtable-ref h '(zippo) 'nil) 'nil)
1255  (begin
1256    (define h3 (hashtable-copy h2 #f))
1257    (and (hashtable? h3)
1258         (eq-hashtable? h3)
1259         (not (hashtable-mutable? h3))
1260         (eq-hashtable-weak? h3)
1261         (hashtable-weak? h3)))
1262  (equal-entries? h2 '#((a) (c)) '#(aval cval))
1263  (equal-entries? h3 '#((a) (c)) '#(aval cval))
1264  (equal?
1265    (begin
1266      (set! ka (void))
1267      (collect (collect-maximum-generation))
1268      (list (hashtable-size h2) (hashtable-size h3)))
1269    '(1 1))
1270  (equal-entries? h2 '#((c)) '#(cval))
1271  (equal-entries? h3 '#((c)) '#(cval))
1272  (eqv?
1273    (begin
1274      (set! h3 (void))
1275      (collect (collect-maximum-generation))
1276      (hashtable-size h2))
1277    1)
1278  (equal-entries? h2 '#((c)) '#(cval))
1279
1280 ; test for proper shrinkage
1281  (eqv?
1282    (let ([ht (make-eq-hashtable 32)])
1283      (for-each
1284        (lambda (k*) (for-each (lambda (k) (hashtable-delete! ht k)) k*))
1285        (let ([k** (map (lambda (x) (map list (make-list 1000)))
1286                        (make-list 100))])
1287          (for-each
1288            (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*))
1289            k**)
1290          k**))
1291      (#%$hashtable-veclen ht))
1292    32)
1293
1294 ; test for proper shrinkage as objects are bwp'd
1295 ; uses delete to trigger final shrinkage
1296  (equal?
1297    (let* ([ht (make-weak-eq-hashtable 32)]
1298           [len (#%$hashtable-veclen ht)])
1299      (hashtable-set! ht 'a 'b)
1300      (for-each
1301        (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*))
1302        (map (lambda (x) (map list (make-list 1000))) (make-list 100)))
1303      (collect (collect-maximum-generation))
1304      (hashtable-delete! ht 'a)
1305      (list (hashtable-size ht) (= (#%$hashtable-veclen ht) len)))
1306    '(0 #t))
1307
1308  ; test that weak-hashtable values *do* make keys reachable
1309  (let ([wk1 (list 1)]
1310        [wk2 (list 2)]
1311        [wk3 (list 3)]
1312        [wk4 (list 4)]
1313        [ht (make-weak-eq-hashtable)])
1314    (hashtable-set! ht wk1 wk1)
1315    (hashtable-set! ht wk2 wk1)
1316    (hashtable-set! ht wk3 wk3)
1317    (hashtable-set! ht wk4 wk2)
1318    (collect (collect-maximum-generation))
1319    (and
1320     (equal-entries? ht '#((1) (2) (3) (4)) '#((1) (1) (3) (2)))
1321     (equal? (hashtable-ref ht wk1 #f) wk1)
1322     (equal? (hashtable-ref ht wk2 #f) wk1)
1323     (equal? (hashtable-ref ht wk3 #f) wk3)
1324     (equal? (hashtable-ref ht wk4 #f) wk2)
1325     (begin
1326       (set! wk1 #f)
1327       (set! wk2 #f)
1328       (set! wk3 #f)
1329       (collect (collect-maximum-generation))
1330       (and
1331        (equal-entries? ht '#((1) (2) (3) (4)) '#((1) (1) (3) (2)))
1332        (equal? (hashtable-ref ht wk4 #f) '(2))
1333        (begin
1334          (set! wk4 #f)
1335          (collect (collect-maximum-generation))
1336          (equal-entries? ht '#((1) (2) (3)) '#((1) (1) (3))))))))
1337)
1338
1339(mat ephemeron-eq-hashtable
1340  (begin
1341    (define ka (list 'a)) ; will map to self  \ Doesn't do anything to check
1342    (define kb (list 'b)) ; will map to kc \  | ephemeronness, but just in
1343    (define kc (list 'c)) ; will map to kb /  / case.
1344    (define kq (list 'q))
1345    (define ky (list 'y))
1346    (define kz (list 'z))
1347    #t)
1348  (begin
1349    (define h (make-ephemeron-eq-hashtable 32))
1350    (and (hashtable? h)
1351         (eq-hashtable? h)
1352         (hashtable-mutable? h)
1353         (hashtable-ephemeron? h)
1354         (eq-hashtable-ephemeron? h)))
1355  (eq? (hashtable-hash-function h) #f)
1356  (eq? (hashtable-equivalence-function h) eq?)
1357  (equal? (hashtable-size h) 0)
1358  (equal-entries? h '#() '#())
1359  (eqv? (hashtable-set! h ka ka) (void))
1360  (equal?
1361    (list
1362       (hashtable-contains? h ka)
1363       (hashtable-contains? h kb)
1364       (hashtable-contains? h kc))
1365    '(#t #f #f))
1366  (eqv? (hashtable-set! h kb kc) (void))
1367  (equal?
1368    (list
1369       (hashtable-contains? h ka)
1370       (hashtable-contains? h kb)
1371       (hashtable-contains? h kc))
1372    '(#t #t #f))
1373  (eqv? (hashtable-set! h kc kb) (void))
1374  (equal?
1375    (list
1376       (hashtable-contains? h ka)
1377       (hashtable-contains? h kb)
1378       (hashtable-contains? h kc))
1379    '(#t #t #t))
1380  (equal? (hashtable-size h) 3)
1381  (equal-entries? h '#((a) (b) (c)) '#((a) (c) (b)))
1382  (andmap ephemeron-pair? (vector->list (hashtable-cells h)))
1383  #;(same-elements? (list->vector (hashtable-map h cons)) '#(((a) . a) ((b) . c) ((c) . b)))
1384  #;(same-elements?
1385    (let ([v (make-vector 3)] [i 0])
1386      (hashtable-for-each h (lambda (key val) (vector-set! v i (cons key val)) (set! i (fx+ i 1))))
1387      v)
1388    '#(((a) . a) ((b) . c) ((c) . b)))
1389  #;(same-elements?
1390    (let ([v (make-vector 3)] [i 0])
1391      (hashtable-for-each-cell h (lambda (a) (vector-set! v i a) (set! i (fx+ i 1))))
1392      v)
1393    '#(((a) . a) ((b) . c) ((c) . b)))
1394  (equal? (hashtable-ref h ka 1) '(a))
1395  (equal? (hashtable-ref h kb #f) '(c))
1396  (equal? (hashtable-ref h kc 'nope) '(b))
1397  (eqv? (hashtable-delete! h kb) (void))
1398  (equal? (hashtable-size h) 2)
1399  (equal-entries? h '#((a) (c)) '#((a) (b)))
1400  (begin
1401    (define h2 (hashtable-copy h #t))
1402    (and (hashtable? h2)
1403         (eq-hashtable? h2)
1404         (hashtable-mutable? h2)
1405         (eq-hashtable-ephemeron? h2)
1406         (hashtable-ephemeron? h2)))
1407  (eq? (hashtable-hash-function h2) #f)
1408  (eq? (hashtable-equivalence-function h2) eq?)
1409  (equal? (hashtable-size h2) 2)
1410  (equal-entries? h2 '#((a) (c)) '#((a) (b)))
1411  (eqv? (hashtable-clear! h 4) (void))
1412  (equal?
1413    (list
1414      (hashtable-size h)
1415      (hashtable-ref h ka 1)
1416      (hashtable-ref h kb #f)
1417      (hashtable-ref h kc 'nope))
1418   '(0 1 #f nope))
1419  (equal-entries? h '#() '#())
1420  (equal?
1421    (list
1422      (hashtable-size h2)
1423      (hashtable-ref h2 ka 1)
1424      (hashtable-ref h2 kb #f)
1425      (hashtable-ref h2 kc 'nope))
1426    '(2 (a) #f (b)))
1427  (equal-entries? h2 '#((a) (c)) '#((a) (b)))
1428  (eqv?
1429    (hashtable-update! h kq
1430      (lambda (x) (+ x 1))
1431      17)
1432    (void))
1433  (equal? (hashtable-ref h kq #f) 18)
1434  (eqv?
1435    (hashtable-update! h kq
1436      (lambda (x) (+ x 1))
1437      17)
1438    (void))
1439  (equal? (hashtable-ref h kq #f) 19)
1440  (equal? (hashtable-size h) 1)
1441  (equal-entries? h '#((q)) '#(19))
1442  (eqv?
1443    (begin
1444      (set! kq (void))
1445      (collect (collect-maximum-generation))
1446      (hashtable-size h))
1447    0)
1448  (equal-entries? h '#() '#())
1449  #;(eqv? (hashtable-map h (lambda args (error #f "oops"))) '())
1450  #;(eqv? (hashtable-for-each h (lambda args (error #f "oops"))) (void))
1451  #;(eqv? (hashtable-for-each-cell h (lambda args (error #f "oops"))) (void))
1452  (equal? (hashtable-ref h ky #f) #f)
1453  (eqv?
1454    (hashtable-set! h ky 'toad)
1455    (void))
1456  (equal? (hashtable-ref h ky #f) 'toad)
1457  (equal? (hashtable-ref h kz #f) #f)
1458  (eqv?
1459    (hashtable-update! h kz list 'frog)
1460    (void))
1461  (equal? (hashtable-ref h kz #f) '(frog))
1462  (equal-entries?
1463    h
1464    (vector kz ky)
1465    (vector (hashtable-ref h kz #f) 'toad))
1466  (eqv? (hashtable-ref h '(zippo) 'nil) 'nil)
1467  (begin
1468    (define h3 (hashtable-copy h2 #f))
1469    (and (hashtable? h3)
1470         (eq-hashtable? h3)
1471         (not (hashtable-mutable? h3))
1472         (eq-hashtable-ephemeron? h3)
1473         (hashtable-ephemeron? h3)))
1474  (equal-entries? h2 '#((a) (c)) '#((a) (b)))
1475  (equal-entries? h3 '#((a) (c)) '#((a) (b)))
1476  (equal?
1477    (begin
1478      (set! ka (void))
1479      (collect (collect-maximum-generation))
1480      (list (hashtable-size h2) (hashtable-size h3)))
1481    '(1 1))
1482  (equal-entries? h2 '#((c)) '#((b)))
1483  (equal-entries? h3 '#((c)) '#((b)))
1484  (eqv?
1485    (begin
1486      (set! h3 (void))
1487      (collect (collect-maximum-generation))
1488      (hashtable-size h2))
1489    1)
1490  (equal-entries? h2 '#((c)) '#((b)))
1491
1492 ; test for proper shrinkage
1493  (eqv?
1494    (let ([ht (make-eq-hashtable 32)])
1495      (for-each
1496        (lambda (k*) (for-each (lambda (k) (hashtable-delete! ht k)) k*))
1497        (let ([k** (map (lambda (x) (map list (make-list 1000)))
1498                        (make-list 100))])
1499          (for-each
1500            (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*))
1501            k**)
1502          k**))
1503      (#%$hashtable-veclen ht))
1504    32)
1505
1506 ; test for proper shrinkage as objects are bwp'd
1507 ; uses delete to trigger final shrinkage
1508  (equal?
1509    (let* ([ht (make-ephemeron-eq-hashtable 32)]
1510           [len (#%$hashtable-veclen ht)])
1511      (hashtable-set! ht 'a 'b)
1512      (for-each
1513        (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*))
1514        (map (lambda (x) (map list (make-list 1000))) (make-list 100)))
1515      (collect (collect-maximum-generation))
1516      (hashtable-delete! ht 'a)
1517      (list (hashtable-size ht) (= (#%$hashtable-veclen ht) len)))
1518    '(0 #t))
1519
1520  ; test that ephemeron-hashtable values don't make keys reachable
1521  (let ([wk1 (list 1)]
1522        [wk2 (list 2)]
1523        [wk3 (list 3)]
1524        [wk4 (list 4)]
1525        [ht (make-ephemeron-eq-hashtable)])
1526    (hashtable-set! ht wk1 wk1)
1527    (hashtable-set! ht wk2 wk1)
1528    (hashtable-set! ht wk3 wk3)
1529    (hashtable-set! ht wk4 wk2)
1530    (collect (collect-maximum-generation))
1531    (and
1532     (equal-entries? ht '#((1) (2) (3) (4)) '#((1) (1) (3) (2)))
1533     (equal? (hashtable-ref ht wk1 #f) wk1)
1534     (equal? (hashtable-ref ht wk2 #f) wk1)
1535     (equal? (hashtable-ref ht wk3 #f) wk3)
1536     (equal? (hashtable-ref ht wk4 #f) wk2)
1537     (begin
1538       (set! wk1 #f)
1539       (set! wk2 #f)
1540       (set! wk3 #f)
1541       (collect (collect-maximum-generation))
1542       (and
1543        (equal-entries? ht '#((1) (2) (4)) '#((1) (1) (2)))
1544        (equal? (hashtable-ref ht wk4 #f) '(2))
1545        (begin
1546          (set! wk4 #f)
1547          (collect (collect-maximum-generation))
1548          (equal-entries? ht '#() '#()))))))
1549)
1550
1551(mat eq-hashtable-cell
1552  (let ()
1553    (define-record fribble (x))
1554    (define random-object
1555      (lambda (x)
1556        (case (random 9)
1557          [(0) (cons 'a 'b)]
1558          [(1) (vector 'c)]
1559          [(2) (string #\a #\b)]
1560          [(3) (make-fribble 'q)]
1561          [(4) (gensym)]
1562          [(5) (open-output-string)]
1563          [(6) (fxvector 15 55)]
1564          [(7) (lambda () x)]
1565          [else (box 'top)])))
1566    (let ([ls1 (let f ([n 10000])
1567                 (if (fx= n 0)
1568                     '()
1569                     (cons
1570                       (cons (random-object 4) (random-object 7))
1571                       (f (fx- n 1)))))]
1572          [ht (make-eq-hashtable)]
1573          [wht (make-weak-eq-hashtable)]
1574          [eht (make-ephemeron-eq-hashtable)])
1575      (let ([ls2 (map (lambda (a1) (eq-hashtable-cell ht (car a1) (cdr a1))) ls1)]
1576            [ls3 (map (lambda (a1) (hashtable-cell wht (car a1) (cdr a1))) ls1)]
1577            [ls4 (map (lambda (a1) (hashtable-cell eht (car a1) (cdr a1))) ls1)])
1578        (unless (andmap (lambda (a1 a2 a3 a4)
1579                          (and (eq? (car a1) (car a2))
1580                               (eq? (car a2) (car a3))
1581                               (eq? (car a2) (car a4))))
1582                        ls1 ls2 ls3 ls4)
1583          (errorf #f "keys are not eq"))
1584        (unless (andmap (lambda (a1 a2 a3 a4)
1585                          (and (eq? (cdr a1) (cdr a2))
1586                               (eq? (cdr a2) (cdr a3))
1587                               (eq? (cdr a2) (cdr a4))))
1588                        ls1 ls2 ls3 ls4)
1589          (errorf #f "values are not eq"))
1590        (for-each (lambda (a1)
1591                    (let ([o (random-object 3)])
1592                      ;; Value refers to key:
1593                      (hashtable-set! eht o (list o (car a1)))))
1594                  ls1)
1595        (for-each
1596          (lambda (a1)
1597            (when (fx< (random 10) 5)
1598              (set-car! a1 #f)))
1599          ls1)
1600        (let loop ([i (min (expt (collect-generation-radix) (collect-maximum-generation)) 1000)])
1601          (unless (fx= i 0)
1602            (collect)
1603            (unless (andmap (lambda (a2 a3 a4) (and (eq? (car a2) (car a3)) (eq? (car a2) (car a4))))
1604                            ls2 ls3 ls4)
1605              (errorf #f "a2/a3/a4 keys not eq after collection"))
1606            (unless (and (andmap (lambda (a3) (not (bwp-object? (car a3)))) ls3)
1607                         (andmap (lambda (a4) (not (bwp-object? (car a4)))) ls4))
1608              (errorf #f "keys have been bwp'd"))
1609            (loop (fx- i 1))))
1610        (for-each
1611          (lambda (a2)
1612            (hashtable-delete! ht (car a2))
1613            (set-car! a2 #f))
1614          ls2)
1615        (unless (and (equal? (hashtable-keys ht) '#())
1616                     (equal? (hashtable-values ht) '#())
1617                     (zero? (hashtable-size ht)))
1618          (errorf #f "ht has not been cleared out"))
1619        (let loop ([i (min (expt (collect-generation-radix) (collect-maximum-generation)) 1000)])
1620          (unless (fx= i 0)
1621            (collect)
1622            (unless (andmap (lambda (a1 a3 a4)
1623                              (or (not (car a1))
1624                                  (and (eq? (car a1) (car a3))
1625                                       (eq? (car a1) (car a4)))))
1626                            ls1 ls3 ls4)
1627              (errorf #f "a1/a3/a4 keys not eq after collection"))
1628            (loop (fx- i 1))))
1629        (for-each
1630          (lambda (a1 a3 a4)
1631            (unless (or (car a1)
1632                        (and (bwp-object? (car a3))
1633                             (bwp-object? (car a4))))
1634              (errorf #f "~s has not been bwp'd I" (car a3))))
1635          ls1 ls3 ls4)
1636        (for-each (lambda (a1) (set-car! a1 #f)) ls1)
1637        (collect (collect-maximum-generation))
1638        (unless (and (andmap (lambda (a3) (bwp-object? (car a3))) ls3)
1639                     (andmap (lambda (a4) (bwp-object? (car a4))) ls4))
1640          (errorf #f "keys have not been bwp'd II"))
1641        (unless (and (equal? (hashtable-keys wht) '#())
1642                     (equal? (hashtable-values wht) '#())
1643                     (zero? (hashtable-size wht)))
1644          (errorf #f "wht has not been cleared out"))
1645        (unless (and (equal? (hashtable-keys eht) '#())
1646                     (equal? (hashtable-values eht) '#())
1647                     (zero? (hashtable-size eht)))
1648          (errorf #f "eht has not been cleared out"))))
1649    #t)
1650)
1651
1652(mat $nonweak-eq-hashtable
1653  (begin
1654    (define h (make-eq-hashtable 32))
1655    (and (hashtable? h)
1656         (eq-hashtable? h)
1657         (hashtable-mutable? h)
1658         (not (eq-hashtable-weak? h))
1659         (not (hashtable-weak? h))
1660         (not (eq-hashtable-ephemeron? h))
1661         (not (hashtable-ephemeron? h))))
1662  (eq? (hashtable-hash-function h) #f)
1663  (eq? (hashtable-equivalence-function h) eq?)
1664  (equal? (hashtable-size h) 0)
1665  (equal-entries? h '#() '#())
1666  (eqv? (eq-hashtable-set! h 'a 'aval) (void))
1667  (equal?
1668    (list
1669       (eq-hashtable-contains? h 'a)
1670       (eq-hashtable-contains? h 'b)
1671       (eq-hashtable-contains? h 'c))
1672    '(#t #f #f))
1673  (eqv? (eq-hashtable-set! h 'b 'bval) (void))
1674  (equal?
1675    (list
1676       (eq-hashtable-contains? h 'a)
1677       (eq-hashtable-contains? h 'b)
1678       (eq-hashtable-contains? h 'c))
1679    '(#t #t #f))
1680  (eqv? (eq-hashtable-set! h 'c 'cval) (void))
1681  (equal?
1682    (list
1683       (eq-hashtable-contains? h 'a)
1684       (eq-hashtable-contains? h 'b)
1685       (eq-hashtable-contains? h 'c))
1686    '(#t #t #t))
1687  (equal? (hashtable-size h) 3)
1688  (equal-entries? h '#(b c a) '#(bval cval aval))
1689  (equal? (eq-hashtable-ref h 'a 1) 'aval)
1690  (equal? (eq-hashtable-ref h 'b #f) 'bval)
1691  (equal? (eq-hashtable-ref h 'c 'nope) 'cval)
1692  (eqv? (eq-hashtable-delete! h 'b) (void))
1693  (equal? (hashtable-size h) 2)
1694  (equal-entries? h '#(a c) '#(aval cval))
1695  (begin
1696    (define h2 (hashtable-copy h #t))
1697    (and (hashtable? h2)
1698         (eq-hashtable? h2)
1699         (hashtable-mutable? h2)
1700         (not (eq-hashtable-weak? h2))
1701         (not (hashtable-weak? h2))))
1702  (equal? (hashtable-size h2) 2)
1703  (equal-entries? h2 '#(a c) '#(aval cval))
1704  (eqv? (hashtable-clear! h 4) (void))
1705  (equal?
1706    (list
1707      (hashtable-size h)
1708      (eq-hashtable-ref h 'a 1)
1709      (eq-hashtable-ref h 'b #f)
1710      (eq-hashtable-ref h 'c 'nope))
1711   '(0 1 #f nope))
1712  (equal-entries? h '#() '#())
1713  (equal?
1714    (list
1715      (hashtable-size h2)
1716      (eq-hashtable-ref h2 'a 1)
1717      (eq-hashtable-ref h2 'b #f)
1718      (eq-hashtable-ref h2 'c 'nope))
1719    '(2 aval #f cval))
1720  (equal-entries? h2 '#(a c) '#(aval cval))
1721  (eqv?
1722    (eq-hashtable-update! h 'q
1723      (lambda (x) (+ x 1))
1724      17)
1725    (void))
1726  (equal? (eq-hashtable-ref h 'q #f) 18)
1727  (eqv?
1728    (eq-hashtable-update! h 'q
1729      (lambda (x) (+ x 1))
1730      17)
1731    (void))
1732  (equal? (eq-hashtable-ref h 'q #f) 19)
1733  (equal? (hashtable-size h) 1)
1734 ; test hashtable-copy when some keys may have moved
1735  (let ([t (parameterize ([collect-request-handler void])
1736             (let ([h4a (make-eq-hashtable 32)]
1737                   [k* (map list (make-list 100))])
1738               (for-each (lambda (x) (eq-hashtable-set! h4a x x)) k*)
1739               (collect)
1740              ; create copy after collection but before otherwise touching h4a
1741               (let ([h4b (hashtable-copy h4a #t)])
1742                 (andmap
1743                   (lambda (k) (eq? (eq-hashtable-ref h4b k #f) k))
1744                   k*))))])
1745    (collect)
1746    t)
1747
1748 ; test for proper shrinkage, etc.
1749  (equal?
1750    (let* ([ht (make-eq-hashtable)] [minlen (#%$hashtable-veclen ht)])
1751      (define power-of-two? (lambda (n) (fx= (fxbit-count n) 1)))
1752      (let f ([i 0])
1753        (unless (fx= i (expt 2 17))
1754          (let ([k (fx* i 2)])
1755            (eq-hashtable-set! ht k i)
1756            (f (fx+ i 1))
1757            (assert (eq-hashtable-contains? ht k))
1758            (assert (power-of-two? (#%$hashtable-veclen ht)))
1759            (eq-hashtable-delete! ht k))))
1760      (list (hashtable-size ht) (fx= (#%$hashtable-veclen ht) minlen)))
1761    '(0 #t))
1762
1763  (equal?
1764    (let ([ht (make-eq-hashtable 32)])
1765      (define power-of-two? (lambda (n) (fx= (fxbit-count n) 1)))
1766      (let f ([i 0])
1767        (unless (fx= i (expt 2 17))
1768          (let ([k (fx* i 2)])
1769            (eq-hashtable-set! ht k i)
1770            (f (fx+ i 1))
1771            (assert (eq-hashtable-contains? ht k))
1772            (assert (power-of-two? (#%$hashtable-veclen ht)))
1773            (eq-hashtable-delete! ht k))))
1774      (list (hashtable-size ht) (#%$hashtable-veclen ht)))
1775    '(0 32))
1776)
1777
1778(mat $weak-eq-hashtable
1779  (begin
1780    (define ka (list 'a))
1781    (define kb (list 'b))
1782    (define kc (list 'c))
1783    (define kq (list 'q))
1784    (define ky (list 'y))
1785    (define kz (list 'z))
1786    #t)
1787  (begin
1788    (define h (make-weak-eq-hashtable 32))
1789    (and (hashtable? h)
1790         (eq-hashtable? h)
1791         (hashtable-mutable? h)
1792         (eq-hashtable-weak? h)
1793         (hashtable-weak? h)))
1794  (eq? (hashtable-hash-function h) #f)
1795  (eq? (hashtable-equivalence-function h) eq?)
1796  (equal? (hashtable-size h) 0)
1797  (equal-entries? h '#() '#())
1798  (eqv? (eq-hashtable-set! h ka 'aval) (void))
1799  (equal?
1800    (list
1801       (eq-hashtable-contains? h ka)
1802       (eq-hashtable-contains? h kb)
1803       (eq-hashtable-contains? h kc))
1804    '(#t #f #f))
1805  (eqv? (eq-hashtable-set! h kb 'bval) (void))
1806  (equal?
1807    (list
1808       (eq-hashtable-contains? h ka)
1809       (eq-hashtable-contains? h kb)
1810       (eq-hashtable-contains? h kc))
1811    '(#t #t #f))
1812  (eqv? (eq-hashtable-set! h kc 'cval) (void))
1813  (equal?
1814    (list
1815       (eq-hashtable-contains? h ka)
1816       (eq-hashtable-contains? h kb)
1817       (eq-hashtable-contains? h kc))
1818    '(#t #t #t))
1819  (equal? (hashtable-size h) 3)
1820  (equal-entries? h '#((a) (b) (c)) '#(aval bval cval))
1821  (andmap weak-pair? (vector->list (hashtable-cells h)))
1822  (equal? (eq-hashtable-ref h ka 1) 'aval)
1823  (equal? (eq-hashtable-ref h kb #f) 'bval)
1824  (equal? (eq-hashtable-ref h kc 'nope) 'cval)
1825  (eqv? (eq-hashtable-delete! h kb) (void))
1826  (equal? (hashtable-size h) 2)
1827  (equal-entries? h '#((a) (c)) '#(aval cval))
1828  (begin
1829    (define h2 (hashtable-copy h #t))
1830    (and (hashtable? h2)
1831         (eq-hashtable? h2)
1832         (hashtable-mutable? h2)
1833         (hashtable-weak? h2)
1834         (eq-hashtable-weak? h2)))
1835  (equal? (hashtable-size h2) 2)
1836  (equal-entries? h2 '#((a) (c)) '#(aval cval))
1837  (eqv? (hashtable-clear! h 4) (void))
1838  (equal?
1839    (list
1840      (hashtable-size h)
1841      (eq-hashtable-ref h ka 1)
1842      (eq-hashtable-ref h kb #f)
1843      (eq-hashtable-ref h kc 'nope))
1844   '(0 1 #f nope))
1845  (equal-entries? h '#() '#())
1846  (equal?
1847    (list
1848      (hashtable-size h2)
1849      (eq-hashtable-ref h2 ka 1)
1850      (eq-hashtable-ref h2 kb #f)
1851      (eq-hashtable-ref h2 kc 'nope))
1852    '(2 aval #f cval))
1853  (equal-entries? h2 '#((a) (c)) '#(aval cval))
1854  (eqv?
1855    (eq-hashtable-update! h kq
1856      (lambda (x) (+ x 1))
1857      17)
1858    (void))
1859  (equal? (eq-hashtable-ref h kq #f) 18)
1860  (eqv?
1861    (eq-hashtable-update! h kq
1862      (lambda (x) (+ x 1))
1863      17)
1864    (void))
1865  (equal? (eq-hashtable-ref h kq #f) 19)
1866  (equal? (hashtable-size h) 1)
1867  (equal-entries? h '#((q)) '#(19))
1868  (eqv?
1869    (begin
1870      (set! kq (void))
1871      (collect (collect-maximum-generation))
1872      (hashtable-size h))
1873    0)
1874  (equal-entries? h '#() '#())
1875  (equal? (eq-hashtable-ref h ky #f) #f)
1876  (eqv?
1877    (eq-hashtable-set! h ky 'toad)
1878    (void))
1879  (equal? (eq-hashtable-ref h ky #f) 'toad)
1880  (equal? (eq-hashtable-ref h kz #f) #f)
1881  (eqv?
1882    (eq-hashtable-update! h kz list 'frog)
1883    (void))
1884  (equal? (eq-hashtable-ref h kz #f) '(frog))
1885  (equal-entries?
1886    h
1887    (vector kz ky)
1888    (vector (eq-hashtable-ref h kz #f) 'toad))
1889  (eqv? (eq-hashtable-ref h '(zippo) 'nil) 'nil)
1890  (begin
1891    (define h3 (hashtable-copy h2 #f))
1892    (and (hashtable? h3)
1893         (eq-hashtable? h3)
1894         (not (hashtable-mutable? h3))
1895         (eq-hashtable-weak? h3)
1896         (hashtable-weak? h3)))
1897  (equal-entries? h2 '#((a) (c)) '#(aval cval))
1898  (equal-entries? h3 '#((a) (c)) '#(aval cval))
1899  (equal?
1900    (begin
1901      (set! ka (void))
1902      (collect (collect-maximum-generation))
1903      (list (hashtable-size h2) (hashtable-size h3)))
1904    '(1 1))
1905  (equal-entries? h2 '#((c)) '#(cval))
1906  (equal-entries? h3 '#((c)) '#(cval))
1907  (eqv?
1908    (begin
1909      (set! h3 (void))
1910      (collect (collect-maximum-generation))
1911      (hashtable-size h2))
1912    1)
1913  (equal-entries? h2 '#((c)) '#(cval))
1914
1915 ; test for proper shrinkage
1916  (eqv?
1917    (let ([ht (make-eq-hashtable 32)])
1918      (for-each
1919        (lambda (k*) (for-each (lambda (k) (eq-hashtable-delete! ht k)) k*))
1920        (let ([k** (map (lambda (x) (map list (make-list 1000)))
1921                        (make-list 100))])
1922          (for-each
1923            (lambda (k*) (map (lambda (k) (eq-hashtable-set! ht k 75)) k*))
1924            k**)
1925          k**))
1926      (#%$hashtable-veclen ht))
1927    32)
1928
1929 ; test for proper shrinkage as objects are bwp'd
1930 ; uses delete to trigger final shrinkage
1931  (equal?
1932    (let* ([ht (make-weak-eq-hashtable 32)]
1933           [len (#%$hashtable-veclen ht)])
1934      (eq-hashtable-set! ht 'a 'b)
1935      (for-each
1936        (lambda (k*) (map (lambda (k) (eq-hashtable-set! ht k 75)) k*))
1937        (map (lambda (x) (map list (make-list 1000))) (make-list 100)))
1938      (collect (collect-maximum-generation))
1939      (eq-hashtable-delete! ht 'a)
1940      (list (hashtable-size ht) (= (#%$hashtable-veclen ht) len)))
1941    '(0 #t))
1942  )
1943
1944(mat $ephemeron-eq-hashtable
1945  (begin
1946    (define ka (list 'a))
1947    (define kb (list 'b))
1948    (define kc (list 'c))
1949    (define kq (list 'q))
1950    (define ky (list 'y))
1951    (define kz (list 'z))
1952    #t)
1953  (begin
1954    (define h (make-ephemeron-eq-hashtable 32))
1955    (and (hashtable? h)
1956         (eq-hashtable? h)
1957         (hashtable-mutable? h)
1958         (eq-hashtable-ephemeron? h)
1959         (hashtable-ephemeron? h)))
1960  (eq? (hashtable-hash-function h) #f)
1961  (eq? (hashtable-equivalence-function h) eq?)
1962  (equal? (hashtable-size h) 0)
1963  (equal-entries? h '#() '#())
1964  (eqv? (eq-hashtable-set! h ka 'aval) (void))
1965  (equal?
1966    (list
1967       (eq-hashtable-contains? h ka)
1968       (eq-hashtable-contains? h kb)
1969       (eq-hashtable-contains? h kc))
1970    '(#t #f #f))
1971  (eqv? (eq-hashtable-set! h kb 'bval) (void))
1972  (equal?
1973    (list
1974       (eq-hashtable-contains? h ka)
1975       (eq-hashtable-contains? h kb)
1976       (eq-hashtable-contains? h kc))
1977    '(#t #t #f))
1978  (eqv? (eq-hashtable-set! h kc 'cval) (void))
1979  (equal?
1980    (list
1981       (eq-hashtable-contains? h ka)
1982       (eq-hashtable-contains? h kb)
1983       (eq-hashtable-contains? h kc))
1984    '(#t #t #t))
1985  (equal? (hashtable-size h) 3)
1986  (equal-entries? h '#((a) (b) (c)) '#(aval bval cval))
1987  (andmap ephemeron-pair? (vector->list (hashtable-cells h)))
1988  (equal? (eq-hashtable-ref h ka 1) 'aval)
1989  (equal? (eq-hashtable-ref h kb #f) 'bval)
1990  (equal? (eq-hashtable-ref h kc 'nope) 'cval)
1991  (eqv? (eq-hashtable-delete! h kb) (void))
1992  (equal? (hashtable-size h) 2)
1993  (equal-entries? h '#((a) (c)) '#(aval cval))
1994  (begin
1995    (define h2 (hashtable-copy h #t))
1996    (and (hashtable? h2)
1997         (eq-hashtable? h2)
1998         (hashtable-mutable? h2)
1999         (hashtable-ephemeron? h2)
2000         (eq-hashtable-ephemeron? h2)))
2001  (equal? (hashtable-size h2) 2)
2002  (equal-entries? h2 '#((a) (c)) '#(aval cval))
2003  (eqv? (hashtable-clear! h 4) (void))
2004  (equal?
2005    (list
2006      (hashtable-size h)
2007      (eq-hashtable-ref h ka 1)
2008      (eq-hashtable-ref h kb #f)
2009      (eq-hashtable-ref h kc 'nope))
2010   '(0 1 #f nope))
2011  (equal-entries? h '#() '#())
2012  (equal?
2013    (list
2014      (hashtable-size h2)
2015      (eq-hashtable-ref h2 ka 1)
2016      (eq-hashtable-ref h2 kb #f)
2017      (eq-hashtable-ref h2 kc 'nope))
2018    '(2 aval #f cval))
2019  (equal-entries? h2 '#((a) (c)) '#(aval cval))
2020  (eqv?
2021    (eq-hashtable-update! h kq
2022      (lambda (x) (+ x 1))
2023      17)
2024    (void))
2025  (equal? (eq-hashtable-ref h kq #f) 18)
2026  (eqv?
2027    (eq-hashtable-update! h kq
2028      (lambda (x) (+ x 1))
2029      17)
2030    (void))
2031  (equal? (eq-hashtable-ref h kq #f) 19)
2032  (equal? (hashtable-size h) 1)
2033  (equal-entries? h '#((q)) '#(19))
2034  (eqv?
2035    (begin
2036      (set! kq (void))
2037      (collect (collect-maximum-generation))
2038      (hashtable-size h))
2039    0)
2040  (equal-entries? h '#() '#())
2041  (equal? (eq-hashtable-ref h ky #f) #f)
2042  (eqv?
2043    (eq-hashtable-set! h ky 'toad)
2044    (void))
2045  (equal? (eq-hashtable-ref h ky #f) 'toad)
2046  (equal? (eq-hashtable-ref h kz #f) #f)
2047  (eqv?
2048    (eq-hashtable-update! h kz list 'frog)
2049    (void))
2050  (equal? (eq-hashtable-ref h kz #f) '(frog))
2051  (equal-entries?
2052    h
2053    (vector kz ky)
2054    (vector (eq-hashtable-ref h kz #f) 'toad))
2055  (eqv? (eq-hashtable-ref h '(zippo) 'nil) 'nil)
2056  (begin
2057    (define h3 (hashtable-copy h2 #f))
2058    (and (hashtable? h3)
2059         (eq-hashtable? h3)
2060         (not (hashtable-mutable? h3))
2061         (eq-hashtable-ephemeron? h3)
2062         (hashtable-ephemeron? h3)))
2063  (equal-entries? h2 '#((a) (c)) '#(aval cval))
2064  (equal-entries? h3 '#((a) (c)) '#(aval cval))
2065  (equal?
2066    (begin
2067      (set! ka (void))
2068      (collect (collect-maximum-generation))
2069      (list (hashtable-size h2) (hashtable-size h3)))
2070    '(1 1))
2071  (equal-entries? h2 '#((c)) '#(cval))
2072  (equal-entries? h3 '#((c)) '#(cval))
2073  (eqv?
2074    (begin
2075      (set! h3 (void))
2076      (collect (collect-maximum-generation))
2077      (hashtable-size h2))
2078    1)
2079  (equal-entries? h2 '#((c)) '#(cval))
2080
2081 ; test for proper shrinkage
2082  (eqv?
2083    (let ([ht (make-eq-hashtable 32)])
2084      (for-each
2085        (lambda (k*) (for-each (lambda (k) (eq-hashtable-delete! ht k)) k*))
2086        (let ([k** (map (lambda (x) (map list (make-list 1000)))
2087                        (make-list 100))])
2088          (for-each
2089            (lambda (k*) (map (lambda (k) (eq-hashtable-set! ht k 75)) k*))
2090            k**)
2091          k**))
2092      (#%$hashtable-veclen ht))
2093    32)
2094
2095 ; test for proper shrinkage as objects are bwp'd
2096 ; uses delete to trigger final shrinkage
2097  (equal?
2098    (let* ([ht (make-ephemeron-eq-hashtable 32)]
2099           [len (#%$hashtable-veclen ht)])
2100      (eq-hashtable-set! ht 'a 'b)
2101      (for-each
2102        (lambda (k*) (map (lambda (k) (eq-hashtable-set! ht k 75)) k*))
2103        (map (lambda (x) (map list (make-list 1000))) (make-list 100)))
2104      (collect (collect-maximum-generation))
2105      (eq-hashtable-delete! ht 'a)
2106      (list (hashtable-size ht) (= (#%$hashtable-veclen ht) len)))
2107    '(0 #t))
2108)
2109
2110(mat eq-strange
2111  (begin
2112    (define $ht (make-eq-hashtable))
2113    (define $wht (make-weak-eq-hashtable))
2114    (define $eht (make-ephemeron-eq-hashtable))
2115    (and (hashtable? $ht)
2116         (eq-hashtable? $ht)
2117         (hashtable? $wht)
2118         (eq-hashtable? $wht)
2119         (hashtable? $eht)
2120         (eq-hashtable? $eht)))
2121  (eqv? (hashtable-set! $ht #f 75) (void))
2122  (eqv? (hashtable-ref $ht #f 80) 75)
2123  (eqv? (hashtable-set! $wht #f 75) (void))
2124  (eqv? (hashtable-ref $wht #f 80) 75)
2125  (eqv? (hashtable-set! $eht #f 75) (void))
2126  (eqv? (hashtable-ref $eht #f 80) 75)
2127  (eqv? (hashtable-set! $ht #!bwp "hello") (void))
2128  (equal? (hashtable-ref $ht #!bwp "goodbye") "hello")
2129  (eqv? (hashtable-set! $wht #!bwp "hello") (void))
2130  (and (member (hashtable-ref $wht #!bwp "goodbye") '("hello" "goodbye")) #t)
2131  (eqv? (hashtable-set! $eht #!bwp "hello") (void))
2132  (and (member (hashtable-ref $eht #!bwp "goodbye") '("hello" "goodbye")) #t)
2133 ; make sure that association isn't added before procedure is called
2134  (equal?
2135    (begin
2136      (hashtable-update! $ht 'cupie
2137        (lambda (x) (hashtable-ref $ht 'cupie (cons 'barbie x)))
2138        'doll)
2139      (hashtable-ref $ht 'cupie 'oops))
2140   '(barbie . doll))
2141  (equal?
2142    (begin
2143      (hashtable-update! $wht 'cupie
2144        (lambda (x) (hashtable-ref $wht 'cupie (cons 'barbie x)))
2145        'doll)
2146      (hashtable-ref $wht 'cupie 'oops))
2147   '(barbie . doll))
2148  (equal?
2149    (begin
2150      (hashtable-update! $eht 'cupie
2151        (lambda (x) (hashtable-ref $eht 'cupie (cons 'barbie x)))
2152        'doll)
2153      (hashtable-ref $eht 'cupie 'oops))
2154   '(barbie . doll))
2155)
2156
2157(mat eq-hashtable-stress
2158 ; stress tests
2159  (let () ; nonweak
2160    (define pick
2161      (lambda (ls)
2162        (list-ref ls (random (length ls)))))
2163    (define ht (make-eq-hashtable 4))
2164    (let ([ls (remq '|| (oblist))] [n 50000])
2165      (let f ([i 0] [keep '()] [drop '()])
2166        (if (= i n)
2167            (and (= (hashtable-size ht) (- n (length drop)))
2168                 (andmap (lambda (k)
2169                           (string=?
2170                             (symbol->string (hashtable-ref ht k #f))
2171                             (cond
2172                               [(string? k) k]
2173                               [(pair? k) (car k)]
2174                               [(vector? k) (vector-ref k 0)])))
2175                         keep)
2176                 (andmap (lambda (k) (eq? (hashtable-ref ht k 'no) 'no))
2177                         drop))
2178            (let* ([x (pick ls)] [s (string-copy (symbol->string x))])
2179              (let ([k (case (pick '(string pair vector))
2180                         [(string) s]
2181                         [(pair) (list s)]
2182                         [(vector) (vector s)])])
2183                (hashtable-set! ht k x)
2184                (let ([keep (if (= (modulo i 5) 0) (cons k keep) keep)])
2185                  (if (= (modulo i 17) 5)
2186                      (let ([k (pick keep)])
2187                        (hashtable-delete! ht k)
2188                        (let ([drop (cons k drop)])
2189                          (when (= (random 5) 3)
2190                            (hashtable-delete! ht (pick drop)))
2191                          (f (+ i 1) (remq k keep) drop)))
2192                      (f (+ i 1) keep drop)))))))))
2193
2194  (let () ; weak
2195    (define pick
2196      (lambda (ls)
2197        (list-ref ls (random (length ls)))))
2198    (define ht (make-weak-eq-hashtable 4))
2199    (let ([ls (remq '|| (oblist))] [n 50000])
2200      (let f ([i 0] [keep '()] [drop '()])
2201        (if (= i n)
2202            (and (<= (hashtable-size ht) (- n (length drop)))
2203                 (begin
2204                   (collect (collect-maximum-generation))
2205                   (= (hashtable-size ht) (length keep)))
2206                 (andmap (lambda (k)
2207                           (string=?
2208                             (symbol->string (hashtable-ref ht k #f))
2209                             (cond
2210                               [(string? k) k]
2211                               [(pair? k) (car k)]
2212                               [(vector? k) (vector-ref k 0)])))
2213                         keep)
2214                 (andmap (lambda (k) (eq? (hashtable-ref ht k 'no) 'no))
2215                         drop))
2216            (let* ([x (pick ls)] [s (string-copy (symbol->string x))])
2217              (let ([k (case (pick '(string pair vector))
2218                         [(string) s]
2219                         [(pair) (list s)]
2220                         [(vector) (vector s)])])
2221                (hashtable-set! ht k x)
2222                (let ([keep (if (= (modulo i 5) 0) (cons k keep) keep)])
2223                  (if (= (modulo i 17) 5)
2224                      (let ([k (pick keep)])
2225                        (hashtable-delete! ht k)
2226                        (let ([drop (cons k drop)])
2227                          (when (= (random 5) 3)
2228                            (hashtable-delete! ht (pick drop)))
2229                          (f (+ i 1) (remq k keep) drop)))
2230                      (f (+ i 1) keep drop)))))))))
2231
2232  (let () ; ephemeron
2233    (define pick
2234      (lambda (ls)
2235        (list-ref ls (random (length ls)))))
2236    (define ht (make-ephemeron-eq-hashtable 4))
2237    (let ([ls (remq '|| (oblist))] [n 50000])
2238      (let f ([i 0] [keep '()] [drop '()])
2239        (if (= i n)
2240            (and (<= (hashtable-size ht) (- n (length drop)))
2241                 (begin
2242                   (collect (collect-maximum-generation))
2243                   (= (hashtable-size ht) (length keep)))
2244                 (andmap (lambda (k)
2245                           (string=?
2246                             (symbol->string (hashtable-ref ht k #f))
2247                             (cond
2248                               [(string? k) k]
2249                               [(pair? k) (car k)]
2250                               [(vector? k) (vector-ref k 0)])))
2251                         keep)
2252                 (andmap (lambda (k) (eq? (hashtable-ref ht k 'no) 'no))
2253                         drop))
2254            (let* ([x (pick ls)] [s (string-copy (symbol->string x))])
2255              (let ([k (case (pick '(string pair vector))
2256                         [(string) s]
2257                         [(pair) (list s)]
2258                         [(vector) (vector s)])])
2259                (hashtable-set! ht k x)
2260                (let ([keep (if (= (modulo i 5) 0) (cons k keep) keep)])
2261                  (if (= (modulo i 17) 5)
2262                      (let ([k (pick keep)])
2263                        (hashtable-delete! ht k)
2264                        (let ([drop (cons k drop)])
2265                          (when (= (random 5) 3)
2266                            (hashtable-delete! ht (pick drop)))
2267                          (f (+ i 1) (remq k keep) drop)))
2268                      (f (+ i 1) keep drop)))))))))
2269
2270)
2271
2272(mat nonweak-eqv-hashtable
2273  (begin
2274    (define h (make-eqv-hashtable 32))
2275    (and (hashtable? h)
2276         (not (eq-hashtable? h))
2277         (hashtable-mutable? h)
2278         (not (hashtable-weak? h))
2279         (not (hashtable-ephemeron? h))))
2280  (eq? (hashtable-hash-function h) #f)
2281  (eq? (hashtable-equivalence-function h) eqv?)
2282  (equal? (hashtable-size h) 0)
2283  (equal-entries? h '#() '#())
2284  (eqv? (hashtable-set! h 'a 'aval) (void))
2285  (equal?
2286    (list
2287       (hashtable-contains? h 'a)
2288       (hashtable-contains? h 3.4)
2289       (hashtable-contains? h 'c))
2290    '(#t #f #f))
2291  (eqv? (hashtable-set! h 3.4 'bval) (void))
2292  (equal?
2293    (list
2294       (hashtable-contains? h 'a)
2295       (hashtable-contains? h 3.4)
2296       (hashtable-contains? h 'c))
2297    '(#t #t #f))
2298  (eqv? (hashtable-set! h 'c 'cval) (void))
2299  (equal?
2300    (list
2301       (hashtable-contains? h 'a)
2302       (hashtable-contains? h 3.4)
2303       (hashtable-contains? h 'c))
2304    '(#t #t #t))
2305  (equal? (hashtable-size h) 3)
2306  (equal-entries? h '#(3.4 c a) '#(bval cval aval))
2307  #;(same-elements? (list->vector (hashtable-map h cons)) '#((a . aval) (3.4 . bval) (c . cval)))
2308  #;(same-elements?
2309    (let ([v (make-vector 3)] [i 0])
2310      (hashtable-for-each h (lambda (key val) (vector-set! v i (cons key val)) (set! i (fx+ i 1))))
2311      v)
2312    '#((a . aval) (3.4 . bval) (c . cval)))
2313  #;(same-elements?
2314    (let ([v (make-vector 3)] [i 0])
2315      (hashtable-for-each-cell h (lambda (a) (vector-set! v i a) (set! i (fx+ i 1))))
2316      v)
2317    '#((a . aval) (3.4 . bval) (c . cval)))
2318  (equal? (hashtable-ref h 'a 1) 'aval)
2319  (equal? (hashtable-ref h 3.4 #f) 'bval)
2320  (equal? (hashtable-ref h 'c 'nope) 'cval)
2321  (eqv? (hashtable-delete! h 3.4) (void))
2322  (equal? (hashtable-size h) 2)
2323  (equal-entries? h '#(a c) '#(aval cval))
2324  (begin
2325    (define h2 (hashtable-copy h #t))
2326    (and (hashtable? h2)
2327         (hashtable-mutable? h2)
2328         (not (hashtable-weak? h2))
2329         (not (hashtable-ephemeron? h2))))
2330  (eq? (hashtable-hash-function h2) #f)
2331  (eq? (hashtable-equivalence-function h2) eqv?)
2332  (equal? (hashtable-size h2) 2)
2333  (equal-entries? h2 '#(a c) '#(aval cval))
2334  (eqv? (hashtable-clear! h 4) (void))
2335  (equal?
2336    (list
2337      (hashtable-size h)
2338      (hashtable-ref h 'a 1)
2339      (hashtable-ref h 3.4 #f)
2340      (hashtable-ref h 'c 'nope))
2341   '(0 1 #f nope))
2342  (equal-entries? h '#() '#())
2343  (equal?
2344    (list
2345      (hashtable-size h2)
2346      (hashtable-ref h2 'a 1)
2347      (hashtable-ref h2 3.4 #f)
2348      (hashtable-ref h2 'c 'nope))
2349    '(2 aval #f cval))
2350  (equal-entries? h2 '#(a c) '#(aval cval))
2351  (eqv?
2352    (hashtable-update! h 'q
2353      (lambda (x) (+ x 1))
2354      17)
2355    (void))
2356  (equal? (hashtable-ref h 'q #f) 18)
2357  (eqv?
2358    (hashtable-update! h 'q
2359      (lambda (x) (+ x 1))
2360      17)
2361    (void))
2362  (equal? (hashtable-ref h 'q #f) 19)
2363  (equal? (hashtable-size h) 1)
2364 ; test hashtable-copy when some keys may have moved
2365  (let ([t (parameterize ([collect-request-handler void])
2366             (let ([h4a (make-eqv-hashtable 32)]
2367                   [k* (map list (make-list 100))])
2368               (for-each (lambda (x) (hashtable-set! h4a x x)) k*)
2369               (collect)
2370              ; create copy after collection but before otherwise touching h4a
2371               (let ([h4b (hashtable-copy h4a #t)])
2372                 (andmap
2373                   (lambda (k) (eqv? (hashtable-ref h4b k #f) k))
2374                   k*))))])
2375    (collect)
2376    t)
2377
2378 ; test for proper shrinkage
2379  (equal?
2380    (let ([ht (make-eqv-hashtable 32)])
2381      (for-each
2382        (lambda (k*) (for-each (lambda (k) (hashtable-delete! ht k)) k*))
2383        (let ([k** (map (lambda (x) (map list (make-list 1000)))
2384                        (make-list 100))])
2385          (for-each
2386            (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*))
2387            k**)
2388          k**))
2389      (call-with-values (lambda () (#%$hashtable-veclen ht)) cons))
2390    '(32 . 32))
2391)
2392
2393(mat weak-eqv-hashtable
2394  (begin
2395    (define ka (list 'a))
2396    (define kb (list 'b))
2397    (define kc (list 'c))
2398    (define kq (list 'q))
2399    (define ky (list 'y))
2400    (define kz (list 'z))
2401    (define km -5.75)
2402    (define kn 17)
2403    (define ko (+ (most-positive-fixnum) 5))
2404    #t)
2405  (begin
2406    (define h (make-weak-eqv-hashtable 32))
2407    (and (hashtable? h)
2408         (not (eq-hashtable? h))
2409         (hashtable-mutable? h)
2410         (hashtable-weak? h)))
2411  (eq? (hashtable-hash-function h) #f)
2412  (eq? (hashtable-equivalence-function h) eqv?)
2413  (equal? (hashtable-size h) 0)
2414  (equal-entries? h '#() '#())
2415  (eqv? (hashtable-set! h ka 'aval) (void))
2416  (equal?
2417    (list
2418       (hashtable-contains? h ka)
2419       (hashtable-contains? h kb)
2420       (hashtable-contains? h kc)
2421       (hashtable-contains? h km)
2422       (hashtable-contains? h kn)
2423       (hashtable-contains? h ko))
2424    '(#t #f #f #f #f #f))
2425  (eqv? (hashtable-set! h kb 'bval) (void))
2426  (equal?
2427    (list
2428       (hashtable-contains? h ka)
2429       (hashtable-contains? h kb)
2430       (hashtable-contains? h kc)
2431       (hashtable-contains? h km)
2432       (hashtable-contains? h kn)
2433       (hashtable-contains? h ko))
2434    '(#t #t #f #f #f #f))
2435  (eqv? (hashtable-set! h kc 'cval) (void))
2436  (equal?
2437    (list
2438       (hashtable-contains? h ka)
2439       (hashtable-contains? h kb)
2440       (hashtable-contains? h kc)
2441       (hashtable-contains? h km)
2442       (hashtable-contains? h kn)
2443       (hashtable-contains? h ko))
2444    '(#t #t #t #f #f #f))
2445  (eqv? (hashtable-set! h km 'mval) (void))
2446  (equal?
2447    (list
2448       (hashtable-contains? h ka)
2449       (hashtable-contains? h kb)
2450       (hashtable-contains? h kc)
2451       (hashtable-contains? h km)
2452       (hashtable-contains? h kn)
2453       (hashtable-contains? h ko))
2454    '(#t #t #t #t #f #f))
2455  (eqv? (hashtable-set! h kn 'nval) (void))
2456  (equal?
2457    (list
2458       (hashtable-contains? h ka)
2459       (hashtable-contains? h kb)
2460       (hashtable-contains? h kc)
2461       (hashtable-contains? h km)
2462       (hashtable-contains? h kn)
2463       (hashtable-contains? h ko))
2464    '(#t #t #t #t #t #f))
2465  (eqv? (hashtable-set! h ko 'oval) (void))
2466  (equal?
2467    (list
2468       (hashtable-contains? h ka)
2469       (hashtable-contains? h kb)
2470       (hashtable-contains? h kc)
2471       (hashtable-contains? h km)
2472       (hashtable-contains? h kn)
2473       (hashtable-contains? h ko))
2474    '(#t #t #t #t #t #t))
2475  (equal? (hashtable-size h) 6)
2476  (equal-entries? h `#((a) (b) (c) -5.75 17 ,ko) '#(aval bval cval mval nval oval))
2477  #;(same-elements?
2478    (list->vector (hashtable-map h cons))
2479    `#(((a) . aval) ((b) . bval) ((c) . cval) (-5.75 . mval) (17 . nval) (,ko . oval)))
2480  #;(same-elements?
2481    (let ([v (make-vector 6)] [i 0])
2482      (hashtable-for-each h (lambda (key val) (vector-set! v i (cons key val)) (set! i (fx+ i 1))))
2483      v)
2484    `#(((a) . aval) ((b) . bval) ((c) . cval) (-5.75 . mval) (17 . nval) (,ko . oval)))
2485  #;(same-elements?
2486    (let ([v (make-vector 6)] [i 0])
2487      (hashtable-for-each-cell h (lambda (a) (vector-set! v i a) (set! i (fx+ i 1))))
2488      v)
2489    `#(((a) . aval) ((b) . bval) ((c) . cval) (-5.75 . mval) (17 . nval) (,ko . oval)))
2490  (eq? (hashtable-ref h ka 1) 'aval)
2491  (eq? (hashtable-ref h kb #f) 'bval)
2492  (eq? (hashtable-ref h kc 'nope) 'cval)
2493  (eq? (hashtable-ref h (+ 2 -7.75) 'ugh) 'mval)
2494  (eq? (hashtable-ref h (/ 34 2) 'ugh) 'nval)
2495  (eq? (hashtable-ref h (+ (most-positive-fixnum) 7 -2) 'ugh) 'oval)
2496  (eqv? (hashtable-delete! h kb) (void))
2497  (equal? (hashtable-size h) 5)
2498  (equal-entries? h `#((a) (c) -5.75 17 ,ko) '#(aval cval mval nval oval))
2499  (begin
2500    (define h2 (hashtable-copy h #t))
2501    (and (hashtable? h2)
2502         (hashtable-mutable? h2)
2503         (hashtable-weak? h2)))
2504  (eq? (hashtable-hash-function h2) #f)
2505  (eq? (hashtable-equivalence-function h2) eqv?)
2506  (equal? (hashtable-size h2) 5)
2507  (equal-entries? h `#((a) (c) -5.75 17 ,ko) '#(aval cval mval nval oval))
2508  (eqv? (hashtable-clear! h 4) (void))
2509  (equal?
2510    (list
2511      (hashtable-size h)
2512      (hashtable-ref h ka 1)
2513      (hashtable-ref h kb #f)
2514      (hashtable-ref h kc 'nope)
2515      (hashtable-ref h km 'nope)
2516      (hashtable-ref h kn 'nope)
2517      (hashtable-ref h ko 'nope))
2518   '(0 1 #f nope nope nope nope))
2519  (equal-entries? h '#() '#())
2520  (equal?
2521    (list
2522      (hashtable-size h2)
2523      (hashtable-ref h2 ka 1)
2524      (hashtable-ref h2 kb #f)
2525      (hashtable-ref h2 kc 'nope)
2526      (hashtable-ref h2 (- (+ km 1) 1) 'nope)
2527      (hashtable-ref h2 (- (+ kn 1) 1) 'nope)
2528      (hashtable-ref h2 (- (+ ko 1) 1) 'nope))
2529    '(5 aval #f cval mval nval oval))
2530  (equal-entries? h2 `#((a) (c) -5.75 17 ,ko) '#(aval cval mval nval oval))
2531  (eqv?
2532    (hashtable-update! h kq
2533      (lambda (x) (+ x 1))
2534      17)
2535    (void))
2536  (equal? (hashtable-ref h kq #f) 18)
2537  (eqv?
2538    (hashtable-update! h kq
2539      (lambda (x) (+ x 1))
2540      17)
2541    (void))
2542  (equal? (hashtable-ref h kq #f) 19)
2543  (equal? (hashtable-size h) 1)
2544  (equal-entries? h '#((q)) '#(19))
2545  (eqv?
2546    (begin
2547      (set! kq (void))
2548      (collect (collect-maximum-generation))
2549      (hashtable-size h))
2550    0)
2551  (equal-entries? h '#() '#())
2552  (equal? (hashtable-ref h ky #f) #f)
2553  (eqv?
2554    (hashtable-set! h ky 'toad)
2555    (void))
2556  (equal? (hashtable-ref h ky #f) 'toad)
2557  (equal? (hashtable-ref h kz #f) #f)
2558  (eqv?
2559    (hashtable-update! h kz list 'frog)
2560    (void))
2561  (equal? (hashtable-ref h kz #f) '(frog))
2562  (equal-entries?
2563    h
2564    (vector kz ky)
2565    (vector (hashtable-ref h kz #f) 'toad))
2566  (eqv? (hashtable-ref h '(zippo) 'nil) 'nil)
2567  (begin
2568    (define h3 (hashtable-copy h2 #f))
2569    (and (hashtable? h3)
2570         (not (hashtable-mutable? h3))
2571         (hashtable-weak? h3)))
2572  (equal-entries? h2 `#((a) (c) -5.75 17 ,ko) '#(aval cval mval nval oval))
2573  (equal-entries? h3 `#((a) (c) -5.75 17 ,ko) '#(aval cval mval nval oval))
2574  (equal?
2575    (begin
2576      (set! ka (void))
2577      (set! km (void))
2578      (set! kn (void))
2579      (set! ko (void))
2580      (collect (collect-maximum-generation))
2581      (list (hashtable-size h2) (hashtable-size h3)))
2582    '(4 4))
2583  (equal-entries? h2 `#((c) -5.75 17 ,(+ (most-positive-fixnum) 5)) '#(cval mval nval oval))
2584  (equal-entries? h3 `#((c) -5.75 17 ,(+ (most-positive-fixnum) 5)) '#(cval mval nval oval))
2585  (eqv?
2586    (begin
2587      (set! h3 (void))
2588      (collect (collect-maximum-generation))
2589      (hashtable-size h2))
2590    4)
2591  (equal-entries? h2 `#((c) -5.75 17 ,(+ (most-positive-fixnum) 5)) '#(cval mval nval oval))
2592
2593 ; test for proper shrinkage
2594  (equal?
2595    (let ([ht (make-eqv-hashtable 32)])
2596      (for-each
2597        (lambda (k*) (for-each (lambda (k) (hashtable-delete! ht k)) k*))
2598        (let ([k** (map (lambda (x) (map list (make-list 1000)))
2599                        (make-list 100))])
2600          (for-each
2601            (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*))
2602            k**)
2603          k**))
2604      (call-with-values (lambda () (#%$hashtable-veclen ht)) cons))
2605    '(32 . 32))
2606
2607 ; test for proper shrinkage as objects are bwp'd
2608 ; uses delete to trigger final shrinkage
2609  (equal?
2610    (let ([ht (make-weak-eqv-hashtable 32)])
2611      (hashtable-set! ht 'a 'b)
2612      (for-each
2613        (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*))
2614        (map (lambda (x) (map list (make-list 1000))) (make-list 100)))
2615      (collect (collect-maximum-generation))
2616      (hashtable-delete! ht 'a)
2617      (list (hashtable-size ht)
2618            (let-values ([(n1 n2) (#%$hashtable-veclen ht)])
2619              (= n1 n2 32))))
2620    '(0 #t))
2621  )
2622
2623(mat ephemeron-eqv-hashtable
2624  (begin
2625    (define ka (list 'a))
2626    (define kb (list 'b))
2627    (define kc (list 'c))
2628    (define kq (list 'q))
2629    (define ky (list 'y))
2630    (define kz (list 'z))
2631    (define km -5.75)
2632    (define kn 17)
2633    (define ko (+ (most-positive-fixnum) 5))
2634    #t)
2635  (begin
2636    (define h (make-ephemeron-eqv-hashtable 32))
2637    (and (hashtable? h)
2638         (not (eq-hashtable? h))
2639         (hashtable-mutable? h)
2640         (hashtable-ephemeron? h)))
2641  (eq? (hashtable-hash-function h) #f)
2642  (eq? (hashtable-equivalence-function h) eqv?)
2643  (equal? (hashtable-size h) 0)
2644  (equal-entries? h '#() '#())
2645  (eqv? (hashtable-set! h ka 'aval) (void))
2646  (equal?
2647    (list
2648       (hashtable-contains? h ka)
2649       (hashtable-contains? h kb)
2650       (hashtable-contains? h kc)
2651       (hashtable-contains? h km)
2652       (hashtable-contains? h kn)
2653       (hashtable-contains? h ko))
2654    '(#t #f #f #f #f #f))
2655  (eqv? (hashtable-set! h kb 'bval) (void))
2656  (equal?
2657    (list
2658       (hashtable-contains? h ka)
2659       (hashtable-contains? h kb)
2660       (hashtable-contains? h kc)
2661       (hashtable-contains? h km)
2662       (hashtable-contains? h kn)
2663       (hashtable-contains? h ko))
2664    '(#t #t #f #f #f #f))
2665  (eqv? (hashtable-set! h kc 'cval) (void))
2666  (equal?
2667    (list
2668       (hashtable-contains? h ka)
2669       (hashtable-contains? h kb)
2670       (hashtable-contains? h kc)
2671       (hashtable-contains? h km)
2672       (hashtable-contains? h kn)
2673       (hashtable-contains? h ko))
2674    '(#t #t #t #f #f #f))
2675  (eqv? (hashtable-set! h km 'mval) (void))
2676  (equal?
2677    (list
2678       (hashtable-contains? h ka)
2679       (hashtable-contains? h kb)
2680       (hashtable-contains? h kc)
2681       (hashtable-contains? h km)
2682       (hashtable-contains? h kn)
2683       (hashtable-contains? h ko))
2684    '(#t #t #t #t #f #f))
2685  (eqv? (hashtable-set! h kn 'nval) (void))
2686  (equal?
2687    (list
2688       (hashtable-contains? h ka)
2689       (hashtable-contains? h kb)
2690       (hashtable-contains? h kc)
2691       (hashtable-contains? h km)
2692       (hashtable-contains? h kn)
2693       (hashtable-contains? h ko))
2694    '(#t #t #t #t #t #f))
2695  (eqv? (hashtable-set! h ko 'oval) (void))
2696  (equal?
2697    (list
2698       (hashtable-contains? h ka)
2699       (hashtable-contains? h kb)
2700       (hashtable-contains? h kc)
2701       (hashtable-contains? h km)
2702       (hashtable-contains? h kn)
2703       (hashtable-contains? h ko))
2704    '(#t #t #t #t #t #t))
2705  (equal? (hashtable-size h) 6)
2706  (equal-entries? h `#((a) (b) (c) -5.75 17 ,ko) '#(aval bval cval mval nval oval))
2707  #;(same-elements?
2708    (list->vector (hashtable-map h cons))
2709    `#(((a) . aval) ((b) . bval) ((c) . cval) (-5.75 . mval) (17 . nval) (,ko . oval)))
2710  #;(same-elements?
2711    (let ([v (make-vector 6)] [i 0])
2712      (hashtable-for-each h (lambda (key val) (vector-set! v i (cons key val)) (set! i (fx+ i 1))))
2713      v)
2714    `#(((a) . aval) ((b) . bval) ((c) . cval) (-5.75 . mval) (17 . nval) (,ko . oval)))
2715  #;(same-elements?
2716    (let ([v (make-vector 6)] [i 0])
2717      (hashtable-for-each-cell h (lambda (a) (vector-set! v i a) (set! i (fx+ i 1))))
2718      v)
2719    `#(((a) . aval) ((b) . bval) ((c) . cval) (-5.75 . mval) (17 . nval) (,ko . oval)))
2720  (eq? (hashtable-ref h ka 1) 'aval)
2721  (eq? (hashtable-ref h kb #f) 'bval)
2722  (eq? (hashtable-ref h kc 'nope) 'cval)
2723  (eq? (hashtable-ref h (+ 2 -7.75) 'ugh) 'mval)
2724  (eq? (hashtable-ref h (/ 34 2) 'ugh) 'nval)
2725  (eq? (hashtable-ref h (+ (most-positive-fixnum) 7 -2) 'ugh) 'oval)
2726  (eqv? (hashtable-delete! h kb) (void))
2727  (equal? (hashtable-size h) 5)
2728  (equal-entries? h `#((a) (c) -5.75 17 ,ko) '#(aval cval mval nval oval))
2729  (begin
2730    (define h2 (hashtable-copy h #t))
2731    (and (hashtable? h2)
2732         (hashtable-mutable? h2)
2733         (hashtable-ephemeron? h2)))
2734  (eq? (hashtable-hash-function h2) #f)
2735  (eq? (hashtable-equivalence-function h2) eqv?)
2736  (equal? (hashtable-size h2) 5)
2737  (equal-entries? h `#((a) (c) -5.75 17 ,ko) '#(aval cval mval nval oval))
2738  (eqv? (hashtable-clear! h 4) (void))
2739  (equal?
2740    (list
2741      (hashtable-size h)
2742      (hashtable-ref h ka 1)
2743      (hashtable-ref h kb #f)
2744      (hashtable-ref h kc 'nope)
2745      (hashtable-ref h km 'nope)
2746      (hashtable-ref h kn 'nope)
2747      (hashtable-ref h ko 'nope))
2748   '(0 1 #f nope nope nope nope))
2749  (equal-entries? h '#() '#())
2750  (equal?
2751    (list
2752      (hashtable-size h2)
2753      (hashtable-ref h2 ka 1)
2754      (hashtable-ref h2 kb #f)
2755      (hashtable-ref h2 kc 'nope)
2756      (hashtable-ref h2 (- (+ km 1) 1) 'nope)
2757      (hashtable-ref h2 (- (+ kn 1) 1) 'nope)
2758      (hashtable-ref h2 (- (+ ko 1) 1) 'nope))
2759    '(5 aval #f cval mval nval oval))
2760  (equal-entries? h2 `#((a) (c) -5.75 17 ,ko) '#(aval cval mval nval oval))
2761  (eqv?
2762    (hashtable-update! h kq
2763      (lambda (x) (+ x 1))
2764      17)
2765    (void))
2766  (equal? (hashtable-ref h kq #f) 18)
2767  (eqv?
2768    (hashtable-update! h kq
2769      (lambda (x) (+ x 1))
2770      17)
2771    (void))
2772  (equal? (hashtable-ref h kq #f) 19)
2773  (equal? (hashtable-size h) 1)
2774  (equal-entries? h '#((q)) '#(19))
2775  (eqv?
2776    (begin
2777      (set! kq (void))
2778      (collect (collect-maximum-generation))
2779      (hashtable-size h))
2780    0)
2781  (equal-entries? h '#() '#())
2782  (equal? (hashtable-ref h ky #f) #f)
2783  (eqv?
2784    (hashtable-set! h ky 'toad)
2785    (void))
2786  (equal? (hashtable-ref h ky #f) 'toad)
2787  (equal? (hashtable-ref h kz #f) #f)
2788  (eqv?
2789    (hashtable-update! h kz list 'frog)
2790    (void))
2791  (equal? (hashtable-ref h kz #f) '(frog))
2792  (equal-entries?
2793    h
2794    (vector kz ky)
2795    (vector (hashtable-ref h kz #f) 'toad))
2796  (eqv? (hashtable-ref h '(zippo) 'nil) 'nil)
2797  (begin
2798    (define h3 (hashtable-copy h2 #f))
2799    (and (hashtable? h3)
2800         (not (hashtable-mutable? h3))
2801         (hashtable-ephemeron? h3)))
2802  (equal-entries? h2 `#((a) (c) -5.75 17 ,ko) '#(aval cval mval nval oval))
2803  (equal-entries? h3 `#((a) (c) -5.75 17 ,ko) '#(aval cval mval nval oval))
2804  (equal?
2805    (begin
2806      (set! ka (void))
2807      (set! km (void))
2808      (set! kn (void))
2809      (set! ko (void))
2810      (collect (collect-maximum-generation))
2811      (list (hashtable-size h2) (hashtable-size h3)))
2812    '(4 4))
2813  (equal-entries? h2 `#((c) -5.75 17 ,(+ (most-positive-fixnum) 5)) '#(cval mval nval oval))
2814  (equal-entries? h3 `#((c) -5.75 17 ,(+ (most-positive-fixnum) 5)) '#(cval mval nval oval))
2815  (eqv?
2816    (begin
2817      (set! h3 (void))
2818      (collect (collect-maximum-generation))
2819      (hashtable-size h2))
2820    4)
2821  (equal-entries? h2 `#((c) -5.75 17 ,(+ (most-positive-fixnum) 5)) '#(cval mval nval oval))
2822
2823 ; test for proper shrinkage
2824  (equal?
2825    (let ([ht (make-eqv-hashtable 32)])
2826      (for-each
2827        (lambda (k*) (for-each (lambda (k) (hashtable-delete! ht k)) k*))
2828        (let ([k** (map (lambda (x) (map list (make-list 1000)))
2829                        (make-list 100))])
2830          (for-each
2831            (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*))
2832            k**)
2833          k**))
2834      (call-with-values (lambda () (#%$hashtable-veclen ht)) cons))
2835    '(32 . 32))
2836
2837 ; test for proper shrinkage as objects are bwp'd
2838 ; uses delete to trigger final shrinkage
2839  (equal?
2840    (let ([ht (make-ephemeron-eqv-hashtable 32)])
2841      (hashtable-set! ht 'a 'b)
2842      (for-each
2843        (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*))
2844        (map (lambda (x) (map list (make-list 1000))) (make-list 100)))
2845      (collect (collect-maximum-generation))
2846      (hashtable-delete! ht 'a)
2847      (list (hashtable-size ht)
2848            (let-values ([(n1 n2) (#%$hashtable-veclen ht)])
2849              (= n1 n2 32))))
2850    '(0 #t))
2851)
2852
2853(mat eqv-hashtable-cell
2854  (let ()
2855    (define-record fribble (x))
2856    (define random-object
2857      (lambda (x)
2858        (case (random 9)
2859          [(0) (cons 'a 3.4)]
2860          [(1) (vector 'c)]
2861          [(2) (string #\a #\b)]
2862          [(3) (make-fribble 'q)]
2863          [(4) (gensym)]
2864          [(5) (open-output-string)]
2865          [(6) (fxvector 15 55)]
2866          [(7) (lambda () x)]
2867          [else (box 'top)])))
2868    (let ([ls1 (let f ([n 10000])
2869                 (if (fx= n 0)
2870                     '()
2871                     (cons
2872                       (cons (random-object 4) (random-object 7))
2873                       (f (fx- n 1)))))]
2874          [ht (make-eqv-hashtable)]
2875          [wht (make-weak-eqv-hashtable)]
2876          [eht (make-ephemeron-eqv-hashtable)])
2877      (let ([ls2 (map (lambda (a1) (hashtable-cell ht (car a1) (cdr a1))) ls1)]
2878            [ls3 (map (lambda (a1) (hashtable-cell wht (car a1) (cdr a1))) ls1)]
2879            [ls4 (map (lambda (a1) (hashtable-cell eht (car a1) (cdr a1))) ls1)])
2880        (unless (andmap (lambda (a1 a2 a3 a4)
2881                          (and (eqv? (car a1) (car a2))
2882                               (eqv? (car a2) (car a3))
2883                               (eqv? (car a2) (car a4))))
2884                        ls1 ls2 ls3 ls4)
2885          (errorf #f "keys are not eqv"))
2886        (unless (andmap (lambda (a1 a2 a3 a4)
2887                          (and (eqv? (cdr a1) (cdr a2))
2888                               (eqv? (cdr a2) (cdr a3))
2889                               (eqv? (cdr a2) (cdr a4))))
2890                        ls1 ls2 ls3 ls4)
2891          (errorf #f "values are not eqv"))
2892        (for-each (lambda (a1)
2893                    (let ([o (random-object 3)])
2894                      ;; Value refers to key:
2895                      (hashtable-set! eht o (list o (car a1)))))
2896                  ls1)
2897        (for-each
2898          (lambda (a1)
2899            (when (fx< (random 10) 5)
2900              (set-car! a1 #f)))
2901          ls1)
2902        (let loop ([i (min (expt (collect-generation-radix) (collect-maximum-generation)) 1000)])
2903          (unless (fx= i 0)
2904            (collect)
2905            (unless (andmap (lambda (a2 a3 a4) (and (eqv? (car a2) (car a3)) (eqv? (car a2) (car a4))))
2906                            ls2 ls3 ls4)
2907              (errorf #f "a2/a3/a4 keys not eqv after collection"))
2908            (unless (and (andmap (lambda (a3) (not (bwp-object? (car a3)))) ls3)
2909                         (andmap (lambda (a4) (not (bwp-object? (car a4)))) ls4))
2910              (errorf #f "keys have been bwp'd"))
2911            (loop (fx- i 1))))
2912        (for-each
2913          (lambda (a2)
2914            (hashtable-delete! ht (car a2))
2915            (set-car! a2 #f))
2916          ls2)
2917        (unless (and (equal? (hashtable-keys ht) '#())
2918                     (equal? (hashtable-values ht) '#())
2919                     (zero? (hashtable-size ht)))
2920          (errorf #f "ht has not been cleared out"))
2921        (let loop ([i (min (expt (collect-generation-radix) (collect-maximum-generation)) 1000)])
2922          (unless (fx= i 0)
2923            (collect)
2924            (unless (andmap (lambda (a1 a3 a4)
2925                              (or (not (car a1))
2926                                  (and (eqv? (car a1) (car a3))
2927                                       (eqv? (car a1) (car a4)))))
2928                            ls1 ls3 ls4)
2929              (errorf #f "a1/a3/a4 keys not eqv after collection"))
2930            (loop (fx- i 1))))
2931        (for-each
2932          (lambda (a1 a3 a4)
2933            (unless (or (car a1)
2934                        (and (bwp-object? (car a3))
2935                             (bwp-object? (car a4))))
2936              (errorf #f "~s has not been bwp'd I" (car a3))))
2937          ls1 ls3 ls4)
2938        (for-each (lambda (a1) (set-car! a1 #f)) ls1)
2939        (collect (collect-maximum-generation))
2940        (unless (and (andmap (lambda (a3) (bwp-object? (car a3))) ls3)
2941                     (andmap (lambda (a4) (bwp-object? (car a4))) ls4))
2942          (errorf #f "keys have not been bwp'd II"))
2943        (unless (and (equal? (hashtable-keys wht) '#())
2944                     (equal? (hashtable-values wht) '#())
2945                     (zero? (hashtable-size wht)))
2946          (errorf #f "wht has not been cleared out"))
2947        (unless (and (equal? (hashtable-keys eht) '#())
2948                     (equal? (hashtable-values eht) '#())
2949                     (zero? (hashtable-size eht)))
2950          (errorf #f "eht has not been cleared out"))))
2951    #t)
2952  )
2953
2954(mat eqv-strange
2955  (begin
2956    (define $ht (make-eqv-hashtable))
2957    (define $wht (make-weak-eqv-hashtable))
2958    (define $eht (make-weak-eqv-hashtable))
2959    (and (hashtable? $ht)
2960         (hashtable? $wht)
2961         (hashtable? $eht)))
2962  (eqv? (hashtable-set! $ht #f 75) (void))
2963  (eqv? (hashtable-ref $ht #f 80) 75)
2964  (eqv? (hashtable-set! $wht #f 75) (void))
2965  (eqv? (hashtable-ref $wht #f 80) 75)
2966  (eqv? (hashtable-set! $eht #f 75) (void))
2967  (eqv? (hashtable-ref $eht #f 80) 75)
2968  (eqv? (hashtable-set! $ht #!bwp "hello") (void))
2969  (equal? (hashtable-ref $ht #!bwp "goodbye") "hello")
2970  (eqv? (hashtable-set! $wht #!bwp "hello") (void))
2971  (eqv? (hashtable-set! $eht #!bwp "hello") (void))
2972  (and (member (hashtable-ref $wht #!bwp "goodbye") '("hello" "goodbye")) #t)
2973  (and (member (hashtable-ref $eht #!bwp "goodbye") '("hello" "goodbye")) #t)
2974 ; make sure that association isn't added before procedure is called
2975  (equal?
2976    (begin
2977      (hashtable-update! $ht 'cupie
2978        (lambda (x) (hashtable-ref $ht 'cupie (cons 'barbie x)))
2979        'doll)
2980      (hashtable-ref $ht 'cupie 'oops))
2981   '(barbie . doll))
2982  (equal?
2983    (begin
2984      (hashtable-update! $wht 'cupie
2985        (lambda (x) (hashtable-ref $wht 'cupie (cons 'barbie x)))
2986        'doll)
2987      (hashtable-ref $wht 'cupie 'oops))
2988   '(barbie . doll))
2989  (equal?
2990    (begin
2991      (hashtable-update! $eht 'cupie
2992        (lambda (x) (hashtable-ref $eht 'cupie (cons 'barbie x)))
2993        'doll)
2994      (hashtable-ref $eht 'cupie 'oops))
2995   '(barbie . doll))
2996)
2997
2998(mat eqv-hashtable-stress
2999 ; stress tests
3000  (let () ; nonweak
3001    (define pick
3002      (lambda (ls)
3003        (list-ref ls (random (length ls)))))
3004    (define ht (make-eqv-hashtable 4))
3005    (let ([ls (remq '|| (oblist))] [n 50000])
3006      (let f ([i 0] [keep '()] [drop '()])
3007        (if (= i n)
3008            (and (= (hashtable-size ht) (- n (length drop)))
3009                 (andmap (lambda (k)
3010                           (string=?
3011                             (symbol->string (hashtable-ref ht k #f))
3012                             (cond
3013                               [(string? k) k]
3014                               [(pair? k) (car k)]
3015                               [(vector? k) (vector-ref k 0)])))
3016                         keep)
3017                 (andmap (lambda (k) (eqv? (hashtable-ref ht k 'no) 'no))
3018                         drop))
3019            (let* ([x (pick ls)] [s (string-copy (symbol->string x))])
3020              (let ([k (case (pick '(string pair vector))
3021                         [(string) s]
3022                         [(pair) (list s)]
3023                         [(vector) (vector s)])])
3024                (hashtable-set! ht k x)
3025                (let ([keep (if (= (modulo i 5) 0) (cons k keep) keep)])
3026                  (if (= (modulo i 17) 5)
3027                      (let ([k (pick keep)])
3028                        (hashtable-delete! ht k)
3029                        (let ([drop (cons k drop)])
3030                          (when (= (random 5) 3)
3031                            (hashtable-delete! ht (pick drop)))
3032                          (f (+ i 1) (remq k keep) drop)))
3033                      (f (+ i 1) keep drop)))))))))
3034
3035  (let () ; weak
3036    (define pick
3037      (lambda (ls)
3038        (list-ref ls (random (length ls)))))
3039    (define ht (make-weak-eqv-hashtable 4))
3040    (let ([ls (remq '|| (oblist))] [n 50000])
3041      (let f ([i 0] [keep '()] [drop '()])
3042        (if (= i n)
3043            (and (<= (hashtable-size ht) (- n (length drop)))
3044                 (begin
3045                   (collect (collect-maximum-generation))
3046                   (= (hashtable-size ht) (length keep)))
3047                 (andmap (lambda (k)
3048                           (string=?
3049                             (symbol->string (hashtable-ref ht k #f))
3050                             (cond
3051                               [(string? k) k]
3052                               [(pair? k) (car k)]
3053                               [(vector? k) (vector-ref k 0)])))
3054                         keep)
3055                 (andmap (lambda (k) (eqv? (hashtable-ref ht k 'no) 'no))
3056                         drop))
3057            (let* ([x (pick ls)] [s (string-copy (symbol->string x))])
3058              (let ([k (case (pick '(string pair vector))
3059                         [(string) s]
3060                         [(pair) (list s)]
3061                         [(vector) (vector s)])])
3062                (hashtable-set! ht k x)
3063                (let ([keep (if (= (modulo i 5) 0) (cons k keep) keep)])
3064                  (if (= (modulo i 17) 5)
3065                      (let ([k (pick keep)])
3066                        (hashtable-delete! ht k)
3067                        (let ([drop (cons k drop)])
3068                          (when (= (random 5) 3)
3069                            (hashtable-delete! ht (pick drop)))
3070                          (f (+ i 1) (remq k keep) drop)))
3071                      (f (+ i 1) keep drop)))))))))
3072
3073  (let () ; ephemeron
3074    (define pick
3075      (lambda (ls)
3076        (list-ref ls (random (length ls)))))
3077    (define ht (make-ephemeron-eqv-hashtable 4))
3078    (let ([ls (remq '|| (oblist))] [n 50000])
3079      (let f ([i 0] [keep '()] [drop '()])
3080        (if (= i n)
3081            (and (<= (hashtable-size ht) (- n (length drop)))
3082                 (begin
3083                   (collect (collect-maximum-generation))
3084                   (= (hashtable-size ht) (length keep)))
3085                 (andmap (lambda (k)
3086                           (string=?
3087                             (symbol->string (hashtable-ref ht k #f))
3088                             (cond
3089                               [(string? k) k]
3090                               [(pair? k) (car k)]
3091                               [(vector? k) (vector-ref k 0)])))
3092                         keep)
3093                 (andmap (lambda (k) (eqv? (hashtable-ref ht k 'no) 'no))
3094                         drop))
3095            (let* ([x (pick ls)] [s (string-copy (symbol->string x))])
3096              (let ([k (case (pick '(string pair vector))
3097                         [(string) s]
3098                         [(pair) (list s)]
3099                         [(vector) (vector s)])])
3100                (hashtable-set! ht k x)
3101                (let ([keep (if (= (modulo i 5) 0) (cons k keep) keep)])
3102                  (if (= (modulo i 17) 5)
3103                      (let ([k (pick keep)])
3104                        (hashtable-delete! ht k)
3105                        (let ([drop (cons k drop)])
3106                          (when (= (random 5) 3)
3107                            (hashtable-delete! ht (pick drop)))
3108                          (f (+ i 1) (remq k keep) drop)))
3109                      (f (+ i 1) keep drop)))))))))
3110
3111)
3112
3113(mat symbol-hashtable
3114  (let ([ht (make-hashtable symbol-hash eq?)])
3115    (and (symbol-hashtable? ht) (eq? (hashtable-equivalence-function ht) eq?)))
3116  (let ([ht (make-hashtable symbol-hash eqv?)])
3117    (and (symbol-hashtable? ht) (eq? (hashtable-equivalence-function ht) eqv?)))
3118  (let ([ht (make-hashtable symbol-hash equal?)])
3119    (and (symbol-hashtable? ht) (eq? (hashtable-equivalence-function ht) equal?)))
3120  (let ([ht (make-hashtable symbol-hash symbol=?)])
3121    (and (symbol-hashtable? ht) (eq? (hashtable-equivalence-function ht) symbol=?)))
3122  (let ([ht (make-hashtable symbol-hash eq? 17)])
3123    (and (symbol-hashtable? ht) (eq? (hashtable-equivalence-function ht) eq?)))
3124  (let ([ht (make-hashtable symbol-hash eqv? 17)])
3125    (and (symbol-hashtable? ht) (eq? (hashtable-equivalence-function ht) eqv?)))
3126  (let ([ht (make-hashtable symbol-hash equal? 17)])
3127    (and (symbol-hashtable? ht) (eq? (hashtable-equivalence-function ht) equal?)))
3128  (let ([ht (make-hashtable symbol-hash symbol=? 17)])
3129    (and (symbol-hashtable? ht) (eq? (hashtable-equivalence-function ht) symbol=?)))
3130  (begin
3131    (define h (make-hashtable symbol-hash eq? 32))
3132    (and (hashtable? h)
3133         (symbol-hashtable? h)
3134         (hashtable-mutable? h)
3135         (not (eq-hashtable? h))
3136         (not (hashtable-weak? h))
3137         (not (hashtable-ephemeron? h))))
3138  (eq? (hashtable-hash-function h) symbol-hash)
3139  (eq? (hashtable-equivalence-function h) eq?)
3140  (equal? (hashtable-size h) 0)
3141  (equal-entries? h '#() '#())
3142  (eqv? (hashtable-set! h 'a 'aval) (void))
3143  (equal?
3144    (list
3145       (hashtable-contains? h 'a)
3146       (hashtable-contains? h 'b)
3147       (hashtable-contains? h 'c))
3148    '(#t #f #f))
3149  (eqv? (hashtable-set! h 'b 'bval) (void))
3150  (equal?
3151    (list
3152       (hashtable-contains? h 'a)
3153       (hashtable-contains? h 'b)
3154       (hashtable-contains? h 'c))
3155    '(#t #t #f))
3156  (eqv? (hashtable-set! h 'c 'cval) (void))
3157  (equal?
3158    (list
3159       (hashtable-contains? h 'a)
3160       (hashtable-contains? h 'b)
3161       (hashtable-contains? h 'c))
3162    '(#t #t #t))
3163  (equal? (hashtable-size h) 3)
3164  (equal-entries? h '#(b c a) '#(bval cval aval))
3165  #;(same-elements? (list->vector (hashtable-map h cons)) '#((a . aval) (b . bval) (c . cval)))
3166  #;(same-elements?
3167    (let ([v (make-vector 3)] [i 0])
3168      (hashtable-for-each h (lambda (key val) (vector-set! v i (cons key val)) (set! i (fx+ i 1))))
3169      v)
3170    '#((a . aval) (b . bval) (c . cval)))
3171  #;(same-elements?
3172    (let ([v (make-vector 3)] [i 0])
3173      (hashtable-for-each-cell h (lambda (a) (vector-set! v i a) (set! i (fx+ i 1))))
3174      v)
3175    '#((a . aval) (b . bval) (c . cval)))
3176  (equal? (hashtable-ref h 'a 1) 'aval)
3177  (equal? (hashtable-ref h 'b #f) 'bval)
3178  (equal? (hashtable-ref h 'c 'nope) 'cval)
3179  (eqv? (hashtable-delete! h 'b) (void))
3180  (equal? (hashtable-size h) 2)
3181  (equal-entries? h '#(a c) '#(aval cval))
3182  (begin
3183    (define h2 (hashtable-copy h #t))
3184    (and (hashtable? h2)
3185         (symbol-hashtable? h2)
3186         (hashtable-mutable? h2)
3187         (not (hashtable-weak? h2))
3188         (not (hashtable-ephemeron? h2))
3189         (not (eq-hashtable? h2))))
3190  (eq? (hashtable-hash-function h2) symbol-hash)
3191  (eq? (hashtable-equivalence-function h2) eq?)
3192  (equal? (hashtable-size h2) 2)
3193  (equal-entries? h2 '#(a c) '#(aval cval))
3194  (eqv? (hashtable-clear! h 4) (void))
3195  (equal?
3196    (list
3197      (hashtable-size h)
3198      (hashtable-ref h 'a 1)
3199      (hashtable-ref h 'b #f)
3200      (hashtable-ref h 'c 'nope))
3201   '(0 1 #f nope))
3202  (equal-entries? h '#() '#())
3203  (equal?
3204    (list
3205      (hashtable-size h2)
3206      (hashtable-ref h2 'a 1)
3207      (hashtable-ref h2 'b #f)
3208      (hashtable-ref h2 'c 'nope))
3209    '(2 aval #f cval))
3210  (equal-entries? h2 '#(a c) '#(aval cval))
3211  (eqv?
3212    (hashtable-update! h 'q
3213      (lambda (x) (+ x 1))
3214      17)
3215    (void))
3216  (equal? (hashtable-ref h 'q #f) 18)
3217  (eqv?
3218    (hashtable-update! h 'q
3219      (lambda (x) (+ x 1))
3220      17)
3221    (void))
3222  (equal? (hashtable-ref h 'q #f) 19)
3223  (equal? (hashtable-size h) 1)
3224 ; test hashtable-copy when some keys may have moved
3225 ; symbol hashes don't change, but keeping test adapted from eq-hashtable mats anyway
3226  (let ([t (parameterize ([collect-request-handler void])
3227             (let ([h4a (make-hashtable symbol-hash eqv? 32)]
3228                   [k* (list-head (oblist) 100)])
3229               (for-each (lambda (x) (hashtable-set! h4a x x)) k*)
3230               (collect)
3231              ; create copy after collection but before otherwise touching h4a
3232               (let ([h4b (hashtable-copy h4a #t)])
3233                 (andmap
3234                   (lambda (k) (eq? (hashtable-ref h4b k #f) k))
3235                   k*))))])
3236    (collect)
3237    t)
3238 ; test for proper shrinkage
3239  (eqv?
3240    (let ([ht (make-hashtable symbol-hash equal? 32)])
3241      (for-each
3242        (lambda (k*) (for-each (lambda (k) (hashtable-delete! ht k)) k*))
3243        (let ([k** (map (lambda (x) (list-head (oblist) 1000)) (make-list 100))])
3244          (for-each
3245            (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*))
3246            k**)
3247          k**))
3248      (#%$hashtable-veclen ht))
3249    32)
3250)
3251
3252(mat $symbol-hashtable
3253  (begin
3254    (define h (make-hashtable symbol-hash eq? 32))
3255    (and (hashtable? h)
3256         (symbol-hashtable? h)
3257         (hashtable-mutable? h)
3258         (not (eq-hashtable? h))
3259         (not (hashtable-weak? h))
3260         (not (hashtable-ephemeron? h))))
3261  (eq? (hashtable-hash-function h) symbol-hash)
3262  (eq? (hashtable-equivalence-function h) eq?)
3263  (equal? (hashtable-size h) 0)
3264  (equal-entries? h '#() '#())
3265  (eqv? (symbol-hashtable-set! h 'a 'aval) (void))
3266  (equal?
3267    (list
3268       (symbol-hashtable-contains? h 'a)
3269       (symbol-hashtable-contains? h 'b)
3270       (symbol-hashtable-contains? h 'c))
3271    '(#t #f #f))
3272  (eqv? (symbol-hashtable-set! h 'b 'bval) (void))
3273  (equal?
3274    (list
3275       (symbol-hashtable-contains? h 'a)
3276       (symbol-hashtable-contains? h 'b)
3277       (symbol-hashtable-contains? h 'c))
3278    '(#t #t #f))
3279  (eqv? (symbol-hashtable-set! h 'c 'cval) (void))
3280  (equal?
3281    (list
3282       (symbol-hashtable-contains? h 'a)
3283       (symbol-hashtable-contains? h 'b)
3284       (symbol-hashtable-contains? h 'c))
3285    '(#t #t #t))
3286  (equal? (hashtable-size h) 3)
3287  (equal-entries? h '#(b c a) '#(bval cval aval))
3288  #;(same-elements? (list->vector (hashtable-map h cons)) '#((a . aval) (b . bval) (c . cval)))
3289  #;(same-elements?
3290    (let ([v (make-vector 3)] [i 0])
3291      (hashtable-for-each h (lambda (key val) (vector-set! v i (cons key val)) (set! i (fx+ i 1))))
3292      v)
3293    '#((a . aval) (b . bval) (c . cval)))
3294  #;(same-elements?
3295    (let ([v (make-vector 3)] [i 0])
3296      (hashtable-for-each-cell h (lambda (a) (vector-set! v i a) (set! i (fx+ i 1))))
3297      v)
3298    '#((a . aval) (b . bval) (c . cval)))
3299  (equal? (symbol-hashtable-ref h 'a 1) 'aval)
3300  (equal? (symbol-hashtable-ref h 'b #f) 'bval)
3301  (equal? (symbol-hashtable-ref h 'c 'nope) 'cval)
3302  (eqv? (symbol-hashtable-delete! h 'b) (void))
3303  (equal? (hashtable-size h) 2)
3304  (equal-entries? h '#(a c) '#(aval cval))
3305  (begin
3306    (define h2 (hashtable-copy h #t))
3307    (and (hashtable? h2)
3308         (symbol-hashtable? h2)
3309         (hashtable-mutable? h2)
3310         (not (hashtable-weak? h2))
3311         (not (hashtable-ephemeron? h2))
3312         (not (eq-hashtable? h2))))
3313  (eq? (hashtable-hash-function h2) symbol-hash)
3314  (eq? (hashtable-equivalence-function h2) eq?)
3315  (equal? (hashtable-size h2) 2)
3316  (equal-entries? h2 '#(a c) '#(aval cval))
3317  (eqv? (hashtable-clear! h 4) (void))
3318  (equal?
3319    (list
3320      (hashtable-size h)
3321      (symbol-hashtable-ref h 'a 1)
3322      (symbol-hashtable-ref h 'b #f)
3323      (symbol-hashtable-ref h 'c 'nope))
3324   '(0 1 #f nope))
3325  (equal-entries? h '#() '#())
3326  (equal?
3327    (list
3328      (hashtable-size h2)
3329      (symbol-hashtable-ref h2 'a 1)
3330      (symbol-hashtable-ref h2 'b #f)
3331      (symbol-hashtable-ref h2 'c 'nope))
3332    '(2 aval #f cval))
3333  (equal-entries? h2 '#(a c) '#(aval cval))
3334  (eqv?
3335    (symbol-hashtable-update! h 'q
3336      (lambda (x) (+ x 1))
3337      17)
3338    (void))
3339  (equal? (symbol-hashtable-ref h 'q #f) 18)
3340  (eqv?
3341    (symbol-hashtable-update! h 'q
3342      (lambda (x) (+ x 1))
3343      17)
3344    (void))
3345  (equal? (symbol-hashtable-ref h 'q #f) 19)
3346  (equal? (hashtable-size h) 1)
3347  (let ([g (gensym)] [s "feisty"])
3348    (let ([a (symbol-hashtable-cell h g s)])
3349      (and (pair? a)
3350           (eq? (car a) g)
3351           (eq? (cdr a) s)
3352           (begin
3353             (hashtable-set! h g 'feisty)
3354             (eq? (cdr a) 'feisty))
3355           (begin
3356             (set-cdr! a (list "feisty"))
3357             (equal? (hashtable-ref h g #f) '("feisty"))))))
3358 ; test hashtable-copy when some keys may have moved
3359 ; symbol hashes don't change, but keeping test adapted from eq-hashtable mats anyway
3360  (let ([t (parameterize ([collect-request-handler void])
3361             (let ([h4a (make-hashtable symbol-hash eqv? 32)]
3362                   [k* (list-head (oblist) 100)])
3363               (for-each (lambda (x) (symbol-hashtable-set! h4a x x)) k*)
3364               (collect)
3365              ; create copy after collection but before otherwise touching h4a
3366               (let ([h4b (hashtable-copy h4a #t)])
3367                 (andmap
3368                   (lambda (k) (eq? (symbol-hashtable-ref h4b k #f) k))
3369                   k*))))])
3370    (collect)
3371    t)
3372 ; test for proper shrinkage
3373  (eqv?
3374    (let ([ht (make-hashtable symbol-hash equal? 32)])
3375      (for-each
3376        (lambda (k*) (for-each (lambda (k) (symbol-hashtable-delete! ht k)) k*))
3377        (let ([k** (map (lambda (x) (list-head (oblist) 1000)) (make-list 100))])
3378          (for-each
3379            (lambda (k*) (map (lambda (k) (symbol-hashtable-set! ht k 75)) k*))
3380            k**)
3381          k**))
3382      (#%$hashtable-veclen ht))
3383    32)
3384)
3385
3386(mat symbol-hashtable-stress
3387 ; stress tests
3388  (let () ; nonweak
3389    (define pick
3390      (lambda (ls)
3391        (list-ref ls (random (length ls)))))
3392    (define ht (make-hashtable symbol-hash eq? 4))
3393    (let ([ls (remq '|| (oblist))] [n 50000])
3394      (let f ([i 0] [keep '()] [drop '()])
3395        (if (= i n)
3396            (and (= (hashtable-size ht) (- n (length drop)))
3397                 (andmap (lambda (k)
3398                           (string=?
3399                             (symbol->string (hashtable-ref ht k #f))
3400                             (symbol->string k)))
3401                         keep)
3402                 (andmap (lambda (k) (eq? (hashtable-ref ht k 'no) 'no))
3403                         drop))
3404            (let* ([x (pick ls)] [s (string-copy (symbol->string x))])
3405              (let ([k (gensym s)])
3406                (hashtable-set! ht k x)
3407                (let ([keep (if (= (modulo i 5) 0) (cons k keep) keep)])
3408                  (if (= (modulo i 17) 5)
3409                      (let ([k (pick keep)])
3410                        (hashtable-delete! ht k)
3411                        (let ([drop (cons k drop)])
3412                          (when (= (random 5) 3)
3413                            (hashtable-delete! ht (pick drop)))
3414                          (f (+ i 1) (remq k keep) drop)))
3415                      (f (+ i 1) keep drop)))))))))
3416)
3417
3418(mat generic-hashtable
3419  (begin
3420    (define $ght-keys1 '#(a b c d e f g))
3421    (define $ght-vals1 '#(1 3 5 7 9 11 13))
3422    (define $ght (make-hashtable equal-hash equal? 8))
3423    (vector-for-each
3424      (lambda (x i) (hashtable-set! $ght x i))
3425      $ght-keys1
3426      $ght-vals1)
3427    (hashtable? $ght))
3428  (not (eq-hashtable? $ght))
3429  (eq? (hashtable-hash-function $ght) equal-hash)
3430  (eq? (hashtable-equivalence-function $ght) equal?)
3431  (eq? (hashtable-mutable? $ght) #t)
3432  (not (hashtable-weak? $ght))
3433  (not (hashtable-ephemeron? $ght))
3434  (eqv? (hashtable-size $ght) (vector-length $ght-keys1))
3435  (eqv? (#%$hashtable-veclen $ght) 8)
3436  (equal-entries? $ght $ght-keys1 $ght-vals1)
3437  (begin
3438    (define $ght-keys2 '#((a . b) (1 . 2) 3/4 3.4 3.5 1e23 #e1e50 1+1i 3+3.2i -15 #e1e-50 #1=(a . #1#) (#2=(#2# b c))))
3439    (define $ght-vals2 '#(a b c d e f g h i j k l m))
3440    (vector-for-each
3441      (lambda (x i) (hashtable-set! $ght x i))
3442      $ght-keys2
3443      $ght-vals2)
3444    (eq? (hashtable-size $ght) (+ (vector-length $ght-keys1) (vector-length $ght-keys2))))
3445  (> (#%$hashtable-veclen $ght) 8)
3446  (equal-entries? $ght ($vector-append $ght-keys1 $ght-keys2) ($vector-append $ght-vals1 $ght-vals2))
3447  #;(same-elements?
3448    (list->vector (hashtable-map $ght cons))
3449    (vector-map cons ($vector-append $ght-keys1 $ght-keys2) ($vector-append $ght-vals1 $ght-vals2)))
3450  #;(same-elements?
3451    (let ([v (make-vector (+ (vector-length $ght-keys1) (vector-length $ght-keys2)))] [i 0])
3452      (hashtable-for-each $ght (lambda (key val) (vector-set! v i (cons key val)) (set! i (fx+ i 1))))
3453      v)
3454    (vector-map cons ($vector-append $ght-keys1 $ght-keys2) ($vector-append $ght-vals1 $ght-vals2)))
3455  #;(same-elements?
3456    (let ([v (make-vector (+ (vector-length $ght-keys1) (vector-length $ght-keys2)))] [i 0])
3457      (hashtable-for-each-cell $ght (lambda (a) (vector-set! v i a) (set! i (fx+ i 1))))
3458      v)
3459    (vector-map cons ($vector-append $ght-keys1 $ght-keys2) ($vector-append $ght-vals1 $ght-vals2)))
3460  ($vector-andmap
3461    (lambda (k v) (equal? (hashtable-ref $ght k #f) v))
3462    $ght-keys1
3463    $ght-vals1)
3464  ($vector-andmap
3465    (lambda (k v) (equal? (hashtable-ref $ght k #f) v))
3466    $ght-keys2
3467    $ght-vals2)
3468  ($vector-andmap
3469    (lambda (k v) (equal? (hashtable-ref $ght k #f) v))
3470    '#((a . b) (1 . 2) 3/4 3.4 3.5 1e23 #e1e50 1+1i 3+3.2i -15 #e1e-50 #3=(a . #3#) (#4=(#4# b c)))
3471    $ght-vals2)
3472  ($vector-andmap
3473    (lambda (k) (hashtable-contains? $ght k))
3474    $ght-keys1)
3475  ($vector-andmap
3476    (lambda (k) (hashtable-contains? $ght k))
3477    $ght-keys2)
3478  (not (hashtable-contains? $ght '(not a key)))
3479  (eq? (hashtable-ref $ght '(not a key) 'not-a-key) 'not-a-key)
3480  (begin
3481    (define $ght2 (hashtable-copy $ght))
3482    (and (hashtable? $ght2)
3483         (not (hashtable-mutable? $ght2))
3484         (not (hashtable-weak? $ght2))
3485         (not (hashtable-ephemeron? $ght2))))
3486  (eq? (hashtable-hash-function $ght) equal-hash)
3487  (eq? (hashtable-equivalence-function $ght) equal?)
3488  (begin
3489    (define $ght3 (hashtable-copy $ght #t))
3490    (and (hashtable? $ght3)
3491         (hashtable-mutable? $ght3)
3492         (not (hashtable-weak? $ght3))
3493         (not (hashtable-ephemeron? $ght3))))
3494  (eq? (hashtable-hash-function $ght) equal-hash)
3495  (eq? (hashtable-equivalence-function $ght) equal?)
3496  (begin
3497    (vector-for-each
3498      (lambda (k) (hashtable-delete! $ght k))
3499      $ght-keys1)
3500    #t)
3501  (equal-entries? $ght $ght-keys2 $ght-vals2)
3502  (eqv? (hashtable-size $ght) (vector-length $ght-keys2))
3503  (begin
3504    (vector-for-each
3505      (lambda (k) (hashtable-delete! $ght k))
3506      $ght-keys2)
3507    #t)
3508  (equal-entries? $ght '#() '#())
3509  (eqv? (hashtable-size $ght) 0)
3510  (eqv? (#%$hashtable-veclen $ght) 8)
3511 ; make sure copies are unaffected by deletions
3512  (eq? (hashtable-size $ght2) (+ (vector-length $ght-keys1) (vector-length $ght-keys2)))
3513  (equal-entries? $ght2 ($vector-append $ght-keys1 $ght-keys2) ($vector-append $ght-vals1 $ght-vals2))
3514  (eq? (hashtable-size $ght3) (+ (vector-length $ght-keys1) (vector-length $ght-keys2)))
3515  (equal-entries? $ght3 ($vector-append $ght-keys1 $ght-keys2) ($vector-append $ght-vals1 $ght-vals2))
3516  (begin
3517    (hashtable-clear! $ght3)
3518    (and
3519      (eqv? (hashtable-size $ght3) 0)
3520      (eqv? (hashtable-size $ght2) (+ (vector-length $ght-keys1) (vector-length $ght-keys2)))))
3521  (error? ; not mutable
3522    (hashtable-clear! $ght2))
3523  (error? ; not mutable
3524    (hashtable-delete! $ght2 (vector-ref $ght-keys2 0)))
3525  (error? ; not mutable
3526    (hashtable-update! $ght2 (vector-ref $ght-keys2 0)
3527      (lambda (x) (cons x x))
3528      'oops))
3529  (error? ; not mutable
3530    (hashtable-update! $ght2 '(not a key)
3531      (lambda (x) (cons x x))
3532      'oops))
3533  (eqv?
3534    (hashtable-update! $ght3 '(a . b)
3535      (lambda (x) (+ x 15))
3536      17)
3537    (void))
3538  (eqv?
3539    (hashtable-update! $ght3 '(a . b)
3540      (lambda (x) (+ x 29))
3541      17)
3542    (void))
3543  (eqv?
3544    (hashtable-update! $ght3 1e23
3545      (lambda (x) (- x 5))
3546      19)
3547    (void))
3548  (equal?
3549    (let ([a (hashtable-cell $ght3 '(a . b) 17)])
3550      (set-cdr! a (+ (cdr a) 100))
3551      a)
3552    '((a . b) . 161))
3553  (equal?
3554    (let ([a (hashtable-cell $ght3 #vu8(1 2 3) 'bv)])
3555      (set-cdr! a (cons (cdr a) 'vb))
3556      a)
3557    '(#vu8(1 2 3) . (bv . vb)))
3558  (equal-entries? $ght3 '#((a . b) 1e23 #vu8(1 2 3)) '#(161 14 (bv . vb)))
3559  (let () ; carl's test program, with a few additions
3560    (define cov:prof-hash
3561      (lambda (V)
3562        (* (vector-ref V 0) (vector-ref V 1) (vector-ref V 2))))
3563    (define cov:prof-equal?
3564      (lambda (V W)
3565        (let ((rv (and (= (vector-ref V 0) (vector-ref W 0))
3566                       (= (vector-ref V 1) (vector-ref W 1))
3567                       (= (vector-ref V 2) (vector-ref W 2)))))
3568          rv)))
3569    (define make-random-vector-key
3570      (lambda ()
3571        (vector (random 20000) (random 100) (random 1000))))
3572    (define test-hash
3573      (lambda (n)
3574        (let ([ht (make-hashtable cov:prof-hash cov:prof-equal?)])
3575          (let loop ([i 0])
3576            (let ([str (make-random-vector-key)])
3577              (hashtable-set! ht str i)
3578              (hashtable-update! ht str (lambda (x) (* x 2)) -1)
3579              (let ([a (hashtable-cell ht str 'a)]) (set-cdr! a (- (cdr a))))
3580              (cond
3581                [(= i n) (= (hashtable-size ht) 1000)]
3582                [(and (hashtable-contains? ht str)
3583                      (= (hashtable-ref ht str #f) (* i -2)))
3584                 (when (= (hashtable-size ht) 1000)
3585                   (hashtable-delete! ht str))
3586                 (loop (+ i 1))]
3587                [else (errorf 'test-hash "hashtable failure for key ~s" str)]))))))
3588    (test-hash 100000))
3589)
3590
3591(mat hash-functions
3592 ; equal-hash
3593  (error? ; wrong argument count
3594    (equal-hash))
3595  (error? ; wrong argument count
3596    (equal-hash 0 0))
3597 ; symbol-hash
3598  (error? ; wrong argument count
3599    (symbol-hash))
3600  (error? ; wrong argument count
3601    (symbol-hash 'a 'a))
3602  (error? ; not a symbol
3603    (symbol-hash "hello"))
3604 ; string-hash
3605  (error? ; wrong argument count
3606    (string-hash))
3607  (error? ; wrong argument count
3608    (string-hash 'a 'a))
3609  (error? ; not a string
3610    (string-hash 'hello))
3611 ; string-ci-hash
3612  (error? ; wrong argument count
3613    (string-ci-hash))
3614  (error? ; wrong argument count
3615    (string-ci-hash 'a 'a))
3616  (error? ; not a string
3617    (string-ci-hash 'hello))
3618  (let ([hc (equal-hash '(a b c))])
3619    (and (integer? hc)
3620         (exact? hc)
3621         (>= hc 0)
3622         (= (equal-hash '(a b c)) hc)))
3623  (let ([hc (string-hash "hello")])
3624    (and (integer? hc)
3625         (exact? hc)
3626         (>= hc 0)
3627         (= (string-hash "hello") hc)))
3628  (let ([hc (string-ci-hash "hello")])
3629    (and (integer? hc)
3630         (exact? hc)
3631         (>= hc 0)
3632         (= (string-ci-hash "HelLo") hc)))
3633  (let f ([ls (oblist)])
3634    (define okay?
3635      (lambda (x)
3636        (let ([hc (symbol-hash x)])
3637          (and (integer? hc)
3638               (exact? hc)
3639               (>= hc 0)
3640               (= (symbol-hash x) hc)))))
3641    (and (okay? (car ls))
3642         (let g ([ls ls] [n 10])
3643           (or (null? ls)
3644               (if (= n 0)
3645                   (f ls)
3646                   (g (cdr ls) (- n 1)))))))
3647 ; adapted from Flatt's r6rs tests for string-ci=?
3648  (eqv? (string-ci-hash "z") (string-ci-hash "Z"))
3649  (not (eqv? (string-ci-hash "z") (string-ci-hash "a")))
3650  (eqv? (string-ci-hash "Stra\xDF;e") (string-ci-hash "Strasse"))
3651  (eqv? (string-ci-hash "Stra\xDF;e") (string-ci-hash "STRASSE"))
3652  (eqv? (string-ci-hash "\x39E;\x391;\x39F;\x3A3;") (string-ci-hash "\x3BE;\x3B1;\x3BF;\x3C2;"))
3653  (eqv? (string-ci-hash "\x39E;\x391;\x39F;\x3A3;") (string-ci-hash "\x3BE;\x3B1;\x3BF;\x3C3;"))
3654)
3655
3656(mat fasl-eq-hashtable
3657 ; fasling out eq hash tables
3658  (equal?
3659    (let ([x (cons 'y '!)])
3660      (define ht (make-eq-hashtable))
3661      (eq-hashtable-set! ht x 'because)
3662      (eq-hashtable-set! ht 'foo "foo")
3663      (let ([p (open-file-output-port "testfile.ss" (file-options replace))])
3664        (fasl-write (list x ht) p)
3665        (close-port p))
3666      (let-values ([(x2 ht2)
3667                    (apply values
3668                      (call-with-port
3669                        (open-file-input-port "testfile.ss")
3670                        fasl-read))])
3671        (list
3672          (eq-hashtable-weak? ht2)
3673          (eq-hashtable-ephemeron? ht2)
3674          (eq-hashtable-ref ht2 x2 #f)
3675          (eq-hashtable-ref ht2 'foo #f))))
3676    '(#f #f because "foo"))
3677 ; fasling out weak eq hash table
3678  (equal?
3679    (with-interrupts-disabled
3680      (let ([x (cons 'y '!)])
3681        (define ht (make-weak-eq-hashtable))
3682        (eq-hashtable-set! ht x 'because)
3683        (eq-hashtable-set! ht 'foo "foo")
3684        (let ([p (open-file-output-port "testfile.ss" (file-options replace))])
3685          (fasl-write (list x ht) p)
3686          (close-port p))
3687        (let-values ([(x2 ht2)
3688                      (apply values
3689                        (call-with-port
3690                          (open-file-input-port "testfile.ss")
3691                          fasl-read))])
3692          (list
3693            (eq-hashtable-weak? ht2)
3694            (eq-hashtable-ephemeron? ht2)
3695            (eq-hashtable-ref ht2 x2 #f)
3696            (eq-hashtable-ref ht2 'foo #f)))))
3697    '(#t #f because "foo"))
3698  (equal?
3699    (let ([ht2 (cadr (call-with-port
3700                       (open-file-input-port "testfile.ss")
3701                       fasl-read))])
3702      (collect (collect-maximum-generation))
3703      (list
3704        (hashtable-keys ht2)
3705        (eq-hashtable-ref ht2 'foo #f)))
3706    '(#(foo) "foo"))
3707 ; fasling out ephemeron eq hash table
3708  (equal?
3709    (with-interrupts-disabled
3710      (let ([x (cons 'y '!)])
3711        (define ht (make-ephemeron-eq-hashtable))
3712        (eq-hashtable-set! ht x 'because)
3713        (eq-hashtable-set! ht 'foo "foo")
3714        (let ([p (open-file-output-port "testfile.ss" (file-options replace))])
3715          (fasl-write (list x ht) p)
3716          (close-port p))
3717        (let-values ([(x2 ht2)
3718                      (apply values
3719                        (call-with-port
3720                          (open-file-input-port "testfile.ss")
3721                          fasl-read))])
3722          (list
3723            (eq-hashtable-weak? ht2)
3724            (eq-hashtable-ephemeron? ht2)
3725            (eq-hashtable-ref ht2 x2 #f)
3726            (eq-hashtable-ref ht2 'foo #f)))))
3727    '(#f #t because "foo"))
3728  (equal?
3729    (let ([ht2 (cadr (call-with-port
3730                       (open-file-input-port "testfile.ss")
3731                       fasl-read))])
3732      (collect (collect-maximum-generation))
3733      (list
3734        (hashtable-keys ht2)
3735        (eq-hashtable-ref ht2 'foo #f)))
3736    '(#(foo) "foo"))
3737 ; fasling eq hash tables via compile-file
3738  (begin
3739    (with-output-to-file "testfile.ss"
3740      (lambda ()
3741        (pretty-print
3742          '(module ($feh-ls $feh-ht)
3743             (define-syntax ls
3744               (let ([ls '(1 2 3)])
3745                 (lambda (x)
3746                   #`(quote #,(datum->syntax #'* ls)))))
3747             (define $feh-ls ls)
3748             (define $feh-ht
3749               (let ()
3750                 (define-syntax a
3751                   (let ([ht (make-eq-hashtable)])
3752                     (eq-hashtable-set! ht 'q 'p)
3753                     (eq-hashtable-set! ht ls (cdr ls))
3754                     (eq-hashtable-set! ht (cdr ls) (cddr ls))
3755                     (eq-hashtable-set! ht (cddr ls) ls)
3756                     (lambda (x) #`(quote #,(datum->syntax #'* ht)))))
3757                 a)))))
3758      'replace)
3759    (compile-file "testfile")
3760    (load "testfile.so")
3761    #t)
3762  (eq? (eq-hashtable-ref $feh-ht 'q #f) 'p)
3763  (eq? (eq-hashtable-ref $feh-ht $feh-ls #f) (cdr $feh-ls))
3764  (eq? (eq-hashtable-ref $feh-ht (cdr $feh-ls) #f) (cddr $feh-ls))
3765  (eq? (eq-hashtable-ref $feh-ht (cddr $feh-ls) #f) $feh-ls)
3766  (begin
3767    (eq-hashtable-set! $feh-ht 'p 'r)
3768    #t)
3769  (eq? (eq-hashtable-ref $feh-ht 'p #f) 'r)
3770  (begin
3771    (eq-hashtable-set! $feh-ht 'q 'not-p)
3772    #t)
3773  (eq? (eq-hashtable-ref $feh-ht 'q #f) 'not-p)
3774)
3775
3776(mat fasl-symbol-hashtable
3777 ; fasling out symbol hash tables
3778  (equal?
3779    (let ()
3780      (define ht (make-hashtable symbol-hash eq?))
3781      (symbol-hashtable-set! ht 'why? 'because)
3782      (symbol-hashtable-set! ht 'foo "foo")
3783      (let ([p (open-file-output-port "testfile.ss" (file-options replace))])
3784        (fasl-write ht p)
3785        (close-port p))
3786      (let ([ht2 (call-with-port (open-file-input-port "testfile.ss") fasl-read)])
3787        (list
3788          (symbol-hashtable-ref ht2 'why? #f)
3789          (symbol-hashtable-ref ht2 'foo #f))))
3790    '(because "foo"))
3791  (#%$fasl-file-equal? "testfile.ss" "testfile.ss")
3792  (eqv? (strip-fasl-file "testfile.ss" "testfile1.ss" (fasl-strip-options)) (void))
3793  (#%$fasl-file-equal? "testfile.ss" "testfile1.ss")
3794  (equal?
3795    (let ([ht2 (call-with-port (open-file-input-port "testfile1.ss" (file-options compressed)) fasl-read)])
3796      (list
3797        (symbol-hashtable-ref ht2 'why? #f)
3798        (symbol-hashtable-ref ht2 'foo #f)))
3799    '(because "foo"))
3800  (begin
3801    (call-with-port (open-file-output-port "testfile1.ss" (file-options replace))
3802      (lambda (p)
3803        (fasl-write (call-with-port (open-file-input-port "testfile.ss") fasl-read) p)))
3804    #t)
3805  (#%$fasl-file-equal? "testfile.ss" "testfile1.ss")
3806  (#%$fasl-file-equal? "testfile1.ss" "testfile.ss")
3807  (begin
3808    (call-with-port (open-file-output-port "testfile1.ss" (file-options replace))
3809      (lambda (p)
3810        (let ([ht (call-with-port (open-file-input-port "testfile.ss") fasl-read)])
3811          (symbol-hashtable-set! ht 'why? 'why-not?)
3812          (fasl-write ht p))))
3813    #t)
3814  (not (#%$fasl-file-equal? "testfile.ss" "testfile1.ss"))
3815  (not (#%$fasl-file-equal? "testfile1.ss" "testfile.ss"))
3816  (begin
3817    (call-with-port (open-file-output-port "testfile1.ss" (file-options replace))
3818      (lambda (p)
3819        (let ([ht (call-with-port (open-file-input-port "testfile.ss") fasl-read)])
3820          (symbol-hashtable-set! ht (gensym) 'foiled)
3821          (fasl-write ht p))))
3822    #t)
3823  (not (#%$fasl-file-equal? "testfile.ss" "testfile1.ss"))
3824  (not (#%$fasl-file-equal? "testfile1.ss" "testfile.ss"))
3825
3826 ; fasling symbol hash tables via compile-file
3827  (begin
3828    (with-output-to-file "testfile.ss"
3829      (lambda ()
3830        (pretty-print
3831          '(define $fsh-ht
3832             (let ()
3833               (define-syntax a
3834                 (let ([ht (make-hashtable symbol-hash symbol=?)])
3835                   (symbol-hashtable-set! ht 'q 'p)
3836                   (symbol-hashtable-set! ht 'p 's)
3837                   (let ([g (gensym "hello")])
3838                     (symbol-hashtable-set! ht g g)
3839                     (symbol-hashtable-set! ht 'g g))
3840                   (lambda (x) #`(quote #,(datum->syntax #'* ht)))))
3841               a))))
3842      'replace)
3843    (compile-file "testfile")
3844    (load "testfile.so")
3845    #t)
3846  (eq? (symbol-hashtable-ref $fsh-ht 'q #f) 'p)
3847  (eq? (symbol-hashtable-ref $fsh-ht 'p #f) 's)
3848  (let ([g (symbol-hashtable-ref $fsh-ht 'g #f)])
3849    (eq? (symbol-hashtable-ref $fsh-ht g #f) g))
3850  (eq? (symbol-hashtable-ref $fsh-ht 'spam #f) #f)
3851  (begin
3852    (symbol-hashtable-set! $fsh-ht 'p 'r)
3853    #t)
3854  (eq? (symbol-hashtable-ref $fsh-ht 'p #f) 'r)
3855  (begin
3856    (symbol-hashtable-set! $fsh-ht 'q 'not-p)
3857    #t)
3858  (eq? (symbol-hashtable-ref $fsh-ht 'q #f) 'not-p)
3859)
3860
3861(mat fasl-other-hashtable
3862 ; can't fasl out other kinds of hashtables
3863  (error?
3864    (let ([x (cons 'y '!)])
3865      (define ht (make-eqv-hashtable))
3866      (hashtable-set! ht x 'because)
3867      (hashtable-set! ht 'foo "foo")
3868      (hashtable-set! ht 3.1415 "pi")
3869      (let ([p (open-file-output-port "testfile.ss" (file-options replace))])
3870        (with-exception-handler
3871          (lambda (c) (close-port p) (raise-continuable c))
3872          (lambda () (fasl-write (list x ht) p))))))
3873  (error?
3874    (let ([x (cons 'y '!)])
3875      (define ht (make-hashtable string-hash string=?))
3876      (hashtable-set! ht "hello" 'goodbye)
3877      (let ([p (open-file-output-port "testfile.ss" (file-options replace))])
3878        (with-exception-handler
3879          (lambda (c) (close-port p) (raise-continuable c))
3880          (lambda () (fasl-write (list x ht) p))))))
3881)
3882
3883(mat ht
3884  (begin
3885    (display-string (separate-eval '(parameterize ([source-directories '("." "../s" "../../s")]) (load "ht.ss"))))
3886    #t)
3887)
3888