;;; hash.ms ;;; Copyright 1984-2016 Cisco Systems, Inc. ;;; ;;; Licensed under the Apache License, Version 2.0 (the "License"); ;;; you may not use this file except in compliance with the License. ;;; You may obtain a copy of the License at ;;; ;;; http://www.apache.org/licenses/LICENSE-2.0 ;;; ;;; Unless required by applicable law or agreed to in writing, software ;;; distributed under the License is distributed on an "AS IS" BASIS, ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ;;; See the License for the specific language governing permissions and ;;; limitations under the License. (mat old-hash-table (error? (get-hash-table '((a . b)) 'a #f)) (error? (put-hash-table! (list (cons 'a 'b)) 'a 'b)) (error? (remove-hash-table! (list (cons 'a 'b)) 'a)) (error? (hash-table-map '((a . b)) cons)) (error? (hash-table-for-each '((a . b)) cons)) (begin (define $h-ht (make-hash-table)) (hash-table? $h-ht)) (not (hash-table? 3)) (not (hash-table? '$h-ht)) (null? (hash-table-map $h-ht list)) (eq? (let ([n 0]) (hash-table-for-each $h-ht (lambda (x y) (set! n (+ n 1)))) n) 0) (equal? (begin (put-hash-table! $h-ht 'ham 'spam) (hash-table-map $h-ht list)) '((ham spam))) (error? ; wrong number of args (hash-table-map $h-ht (lambda (x) x))) (error? ; wrong number of args (hash-table-for-each $h-ht (lambda (x) x))) ((lambda (x y) (or (equal? x y) (equal? x (reverse y)))) (begin (put-hash-table! $h-ht 'cram 'sham) (hash-table-map $h-ht list)) '((ham spam) (cram sham))) ((lambda (x y) (or (equal? x y) (equal? x (reverse y)))) (begin (put-hash-table! $h-ht 'ham 'jam) (hash-table-map $h-ht list)) '((ham jam) (cram sham))) (eq? (get-hash-table $h-ht 'ham #f) 'jam) (eq? (get-hash-table $h-ht 'cram #f) 'sham) (eq? (get-hash-table $h-ht 'sham #f) #f) (equal? (get-hash-table $h-ht 'jam "rats") "rats") (eq? (let ([n 0]) (hash-table-for-each $h-ht (lambda (x y) (set! n (+ n 1)))) n) 2) ((lambda (x y) (or (equal? x y) (equal? x (reverse y)))) (let ([keys '()] [vals '()]) (hash-table-for-each $h-ht (lambda (k v) (set! keys (cons k keys)) (set! vals (cons v vals)))) (map cons vals keys)) '((jam . ham) (sham . cram))) (eq? (collect (collect-maximum-generation)) (void)) ((lambda (x y) (or (equal? x y) (equal? x (reverse y)))) (let ([keys '()] [vals '()]) (hash-table-for-each $h-ht (lambda (k v) (set! keys (cons k keys)) (set! vals (cons v vals)))) (map cons vals keys)) '((jam . ham) (sham . cram))) (eq? (begin (remove-hash-table! $h-ht 'ham) (get-hash-table $h-ht 'ham 'gone!)) 'gone!) (equal? (hash-table-map $h-ht list) '((cram sham))) (eq? (collect (collect-maximum-generation)) (void)) (equal? (hash-table-map $h-ht list) '((cram sham))) (eq? (begin (remove-hash-table! $h-ht 'ham) (get-hash-table $h-ht 'ham 'gone!)) 'gone!) (equal? (hash-table-map $h-ht list) '((cram sham))) (eq? (begin (remove-hash-table! $h-ht 'sham) (get-hash-table $h-ht 'ham 'never-there!)) 'never-there!) (equal? (hash-table-map $h-ht list) '((cram sham))) (eq? (begin (remove-hash-table! $h-ht 'cram) (get-hash-table $h-ht 'cram 'gone-too!)) 'gone-too!) (null? (hash-table-map $h-ht list)) ; fasling out eq hash tables (equal? (let ([x (cons 'y '!)]) (define ht (make-hash-table)) (put-hash-table! ht x 'because) (put-hash-table! ht 'foo "foo") (let ([p (open-file-output-port "testfile.ss" (file-options replace))]) (fasl-write (list x ht) p) (close-port p)) (let-values ([(x2 ht2) (apply values (call-with-port (open-file-input-port "testfile.ss") fasl-read))]) (list (get-hash-table ht2 x2 #f) (get-hash-table ht2 'foo #f)))) '(because "foo")) ; weak hash table tests (begin (define $h-ht (make-hash-table #t)) (hash-table? $h-ht)) (null? (begin (put-hash-table! $h-ht (string #\a) 'yea!) (collect (collect-maximum-generation)) (hash-table-map $h-ht cons))) (eq? (let ([n 0]) (hash-table-for-each $h-ht (lambda (x y) (set! n (+ n 1)))) n) 0) (let ([s (string #\a)]) (put-hash-table! $h-ht s 666) (equal? (get-hash-table $h-ht s #f) 666)) (null? (begin (collect (collect-maximum-generation)) (hash-table-map $h-ht cons))) ; make sure that nonweak hash tables are nonweak (explicit #f arg) (begin (define $h-ht (make-hash-table #f)) (hash-table? $h-ht)) (equal? (begin (put-hash-table! $h-ht (string #\a) "bc") (collect (collect-maximum-generation)) (hash-table-map $h-ht string-append)) '("abc")) ; make sure that nonweak hash tables are nonweak (implicit #f arg) (begin (define $h-ht (make-hash-table)) (hash-table? $h-ht)) (equal? (begin (put-hash-table! $h-ht (string #\a) "bc") (collect (collect-maximum-generation)) (hash-table-map $h-ht string-append)) '("abc")) ; stress tests (let () ; nonweak (define pick (lambda (ls) (list-ref ls (random (length ls))))) (define ht (make-hash-table)) (let* ([ls (remq '|| (oblist))] [n 50000]) (let f ([i 0] [keep '()] [drop '()]) (if (= i n) (and (= (length (hash-table-map ht (lambda (x y) x))) (- n (length drop))) (andmap (lambda (k) (string=? (symbol->string (get-hash-table ht k #f)) (cond [(string? k) k] [(pair? k) (car k)] [(vector? k) (vector-ref k 0)]))) keep) (andmap (lambda (k) (eq? (get-hash-table ht k 'no) 'no)) drop)) (let* ([x (pick ls)] [s (string-copy (symbol->string x))]) (let ([k (case (pick '(string pair vector)) [(string) s] [(pair) (list s)] [(vector) (vector s)])]) (put-hash-table! ht k x) (let ([keep (if (= (modulo i 5) 0) (cons k keep) keep)]) (if (= (modulo i 17) 5) (let ([k (pick keep)]) (remove-hash-table! ht k) (let ([drop (cons k drop)]) (when (= (random 5) 3) (remove-hash-table! ht (pick drop))) (f (+ i 1) (remq k keep) drop))) (f (+ i 1) keep drop))))))))) (let () ; weak (define pick (lambda (ls) (list-ref ls (random (length ls))))) (define ht (make-hash-table #t)) (let* ([ls (remq '|| (oblist))] [n 50000]) (let f ([i 0] [keep '()] [drop '()]) (if (= i n) (and (<= (length (hash-table-map ht (lambda (x y) x))) (- n (length drop))) (begin (collect (collect-maximum-generation)) (= (length (hash-table-map ht (lambda (x y) x))) (length keep))) (andmap (lambda (k) (string=? (symbol->string (get-hash-table ht k #f)) (cond [(string? k) k] [(pair? k) (car k)] [(vector? k) (vector-ref k 0)]))) keep) (andmap (lambda (k) (eq? (get-hash-table ht k 'no) 'no)) drop)) (let* ([x (pick ls)] [s (string-copy (symbol->string x))]) (let ([k (case (pick '(string pair vector)) [(string) s] [(pair) (list s)] [(vector) (vector s)])]) (put-hash-table! ht k x) (let ([keep (if (= (modulo i 5) 0) (cons k keep) keep)]) (if (= (modulo i 17) 5) (let ([k (pick keep)]) (remove-hash-table! ht k) (let ([drop (cons k drop)]) (when (= (random 5) 3) (remove-hash-table! ht (pick drop))) (f (+ i 1) (remq k keep) drop))) (f (+ i 1) keep drop))))))))) ) (mat tlc (critical-section (let () (define ht (make-eq-hashtable)) (define keyval '(a . b)) (define next 0) (define tlc (#%$make-tlc ht keyval next)) (define tlc2 (#%$make-tlc ht keyval next)) (and (#%$tlc? tlc) (not (#%$tlc? keyval)) (eq? (#%$tlc-ht tlc) ht) (eq? (#%$tlc-keyval tlc) keyval) (eqv? (#%$tlc-next tlc) next) (begin (#%$set-tlc-next! tlc tlc2) (eq? (#%$tlc-next tlc) tlc2))))) ) (define $vector-andmap (lambda (p . v*) (apply andmap p (map vector->list v*)))) (define $vector-append (lambda v* (list->vector (apply append (map vector->list v*))))) (define $vector-member? (lambda (x v) (let ([n (vector-length v)]) (let f ([i 0]) (and (not (fx= i n)) (or (equal? (vector-ref v i) x) (f (fx+ i 1)))))))) (define same-elements? (lambda (v1 v2) (let ([n (vector-length v1)]) (define (each-in? v1 v2) (let f ([i 0]) (or (fx= i n) (and ($vector-member? (vector-ref v1 i) v2) (f (fx+ i 1)))))) (and (fx= (vector-length v2) n) (each-in? v1 v2) (each-in? v2 v1))))) (define $equal-entries? (lambda (keys1 vals1 keys2 vals2) (and (same-elements? keys1 keys2) (same-elements? vals1 vals2)))) (define-syntax equal-entries? (syntax-rules () [(_ e1 e2 e3) (let-values ([(keys1 vals1) e1]) ($equal-entries? keys1 vals1 e2 e3))])) (mat hashtable-arguments ; make-eq-hashtable (error? ; wrong argument count (make-eq-hashtable 3 #t)) (error? ; invalid size (make-eq-hashtable -1)) (error? ; invalid size (make-eq-hashtable #t)) (error? ; invalid size (make-eq-hashtable #f)) ; make-hashtable (error? ; wrong argument count (make-hashtable)) (error? ; wrong argument count (make-hashtable equal-hash)) (error? ; wrong argument count (make-hashtable equal-hash equal? 45 53)) (error? ; not a procedure (make-hashtable 'a equal? 45)) (error? ; not a procedure (make-hashtable equal-hash 'a 45)) (error? ; invalid size (make-hashtable equal-hash equal? 'a)) (error? ; invalid size (make-hashtable equal-hash equal? -45)) (error? ; invalid size (make-hashtable equal-hash equal? 45.0)) ; make-eqv-hashtable (error? ; wrong argument count (make-eqv-hashtable 3 #t)) (error? ; invalid size (make-eqv-hashtable -1)) (error? ; invalid size (make-eqv-hashtable #t)) (error? ; invalid size (make-eqv-hashtable #f)) (begin (define $ht (make-eq-hashtable)) (define $imht (hashtable-copy $ht)) (define $ht2 (make-eq-hashtable 50)) (and (hashtable? $ht) (eq-hashtable? $ht) (hashtable-mutable? $ht) (not (hashtable-weak? $ht)) (not (eq-hashtable-weak? $ht)) (hashtable? $imht) (eq-hashtable? $imht) (not (hashtable-mutable? $imht)) (not (hashtable-weak? $imht)) (not (eq-hashtable-weak? $imht)) (hashtable? $ht2) (eq-hashtable? $ht2) (hashtable-mutable? $ht2) (not (hashtable-weak? $ht2)) (not (eq-hashtable-weak? $ht2)))) (not (hashtable? 3)) (not (hashtable? (make-vector 3))) (not (eq-hashtable? 3)) (not (eq-hashtable? (make-vector 3))) ; hashtable? (error? ; wrong argument count (hashtable?)) (error? ; wrong argument count (hashtable? $ht 3)) (error? ; wrong argument count (eq-hashtable?)) (error? ; wrong argument count (eq-hashtable? $ht 3)) ; hashtable-mutable? (error? ; not a hashtable (hashtable-mutable? (make-vector 3))) (error? ; wrong argument count (hashtable-mutable?)) (error? ; wrong argument count (hashtable-mutable? $ht 3)) ; hashtable-size (error? ; wrong argument count (hashtable-size)) (error? ; wrong argument count (hashtable-size $ht 3)) (error? ; not a hashtable (hashtable-size 'hello)) ; hashtable-ref (error? ; wrong argument count (hashtable-ref)) (error? ; wrong argument count (hashtable-ref $ht)) (error? ; wrong argument count (hashtable-ref $ht 'a)) (error? ; wrong argument count (hashtable-ref $ht 'a 'b 'c)) (error? ; not a hashtable (hashtable-ref '(hash . table) 'a 'b)) ; hashtable-contains? (error? ; wrong argument count (hashtable-contains?)) (error? ; wrong argument count (hashtable-contains? $ht)) (error? ; wrong argument count (hashtable-contains? $ht 'a 'b)) (error? ; not a hashtable (hashtable-contains? '(hash . table) 'a)) ; hashtable-set! (error? ; wrong argument count (hashtable-set!)) (error? ; wrong argument count (hashtable-set! $ht)) (error? ; wrong argument count (hashtable-set! $ht 'a)) (error? ; wrong argument count (hashtable-set! $ht 'a 'b 'c)) (error? ; not a hashtable (hashtable-set! '(hash . table) 'a 'b)) (error? ; hashtable not mutable (hashtable-set! $imht 'a 'b)) ; hashtable-update! (error? ; wrong argument count (hashtable-update!)) (error? ; wrong argument count (hashtable-update! $ht)) (error? ; wrong argument count (hashtable-update! $ht 'a values)) (error? ; wrong argument count (hashtable-update! $ht 'a values 'c 'd)) (error? ; not a hashtable (hashtable-update! '(hash . table) 'a values 'b)) (error? ; hashtable not mutable (hashtable-update! $imht 'a values 'b)) (error? ; not a procedure (hashtable-update! $ht 'a "not a procedure" 'b)) ; hashtable-cell (error? ; wrong argument count (hashtable-cell)) (error? ; wrong argument count (hashtable-cell $ht)) (error? ; wrong argument count (hashtable-cell $ht 'a)) (error? ; wrong argument count (hashtable-cell $ht 'a 'b 'c)) (error? ; not a hashtable (hashtable-cell '(hash . table) 'a 'b)) ; hashtable-delete! (error? ; wrong argument count (hashtable-delete!)) (error? ; wrong argument count (hashtable-delete! $ht)) (error? ; wrong argument count (hashtable-delete! $ht 'a 'b)) (error? ; not a hashtable (hashtable-delete! '(hash . table) 'a)) (error? ; hashtable not mutable (hashtable-delete! $imht 'a)) ; hashtable-copy (error? ; wrong argument count (hashtable-copy)) (error? ; wrong argument count (hashtable-copy $ht #t 17)) (error? ; not a hashtable (hashtable-copy '(hash . table) #t)) ; hashtable-clear! (error? ; wrong argument count (hashtable-clear!)) (error? ; wrong argument count (hashtable-clear! $ht 17 'foo)) (error? ; not a hashtable (hashtable-clear! '(hash . table))) (error? ; not a hashtable (hashtable-clear! '(hash . table) 17)) (error? ; hashtable not mutable (hashtable-clear! $imht)) (error? ; hashtable not mutable (hashtable-clear! $imht 32)) (error? ; invalid size (hashtable-clear! $ht #t)) ; hashtable-keys (error? ; wrong argument count (hashtable-keys)) (error? ; wrong argument count (hashtable-keys $ht 72)) (error? ; not a hashtable (hashtable-keys '(hash . table))) ; hashtable-values (error? ; wrong argument count (hashtable-values)) (error? ; wrong argument count (hashtable-values $ht 72)) (error? ; not a hashtable (hashtable-values '(hash . table))) ; hashtable-entries (error? ; wrong argument count (hashtable-entries)) (error? ; wrong argument count (hashtable-entries $ht 72)) (error? ; not a hashtable (hashtable-entries '(hash . table))) ; hashtable-hash-function (error? ; wrong argument count (hashtable-hash-function)) (error? ; wrong argument count (hashtable-hash-function $ht $ht)) (error? ; not a hsshtable (hashtable-hash-function '(hash . table))) ; hashtable-equivalence-function (error? ; wrong argument count (hashtable-equivalence-function)) (error? ; wrong argument count (hashtable-equivalence-function $ht $ht)) (error? ; not a hsshtable (hashtable-equivalence-function '(hash . table))) ; hashtable-weak? (error? ; wrong argument count (hashtable-weak?)) (error? ; wrong argument count (hashtable-weak? $ht 3)) (error? ; not a hashtable (hashtable-weak? '(hash . table))) ) (mat hash-return-value ; hashtable-ref (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) "oops") equal?)]) (hashtable-ref ht 'any #f))) #;(error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) -7) equal?)]) (hashtable-ref ht 'any #f))) (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) 3.5) equal?)]) (hashtable-ref ht 'any #f))) (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) 1+2i) equal?)]) (hashtable-ref ht 'any #f))) ; hashtable-contains? (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) "oops") equal?)]) (hashtable-contains? ht 'any))) #;(error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) -7) equal?)]) (hashtable-contains? ht 'any))) (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) 3.5) equal?)]) (hashtable-contains? ht 'any))) (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) 1+2i) equal?)]) (hashtable-contains? ht 'any))) ; hashtable-set! (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) "oops") equal?)]) (hashtable-set! ht 'any 'spam))) #;(error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) -7) equal?)]) (hashtable-set! ht 'any 'spam))) (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) 3.5) equal?)]) (hashtable-set! ht 'any 'spam))) (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) 1+2i) equal?)]) (hashtable-set! ht 'any 'spam))) ; hashtable-update! (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) "oops") equal?)]) (hashtable-update! ht 'any values 'spam))) #;(error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) -7) equal?)]) (hashtable-update! ht 'any values 'spam))) (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) 3.5) equal?)]) (hashtable-update! ht 'any values 'spam))) (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) 1+2i) equal?)]) (hashtable-update! ht 'any values 'spam))) ; hashtable-cell (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) "oops") equal?)]) (hashtable-cell ht 'any 0))) #;(error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) -7) equal?)]) (hashtable-cell ht 'any 0))) (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) 3.5) equal?)]) (hashtable-cell ht 'any 0))) (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) 1+2i) equal?)]) (hashtable-cell ht 'any 0))) ; hashtable-delete! (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) "oops") equal?)]) (hashtable-delete! ht 'any))) #;(error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) -7) equal?)]) (hashtable-delete! ht 'any))) (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) 3.5) equal?)]) (hashtable-delete! ht 'any))) (error? ; invalid hash-function return value (let ([ht (make-hashtable (lambda (x) 1+2i) equal?)]) (hashtable-delete! ht 'any))) ) (mat eq-hashtable-arguments ; make-weak-eq-hashtable (error? ; wrong argument count (make-weak-eq-hashtable 3 #t)) (error? ; invalid size (make-weak-eq-hashtable -1)) (error? ; invalid size (make-weak-eq-hashtable #t)) (error? ; invalid size (make-weak-eq-hashtable #f)) (begin (define $wht (make-weak-eq-hashtable 50)) (define $imht (hashtable-copy $wht)) (define $wht2 (make-weak-eq-hashtable)) (and (hashtable? $wht) (eq-hashtable? $wht) (hashtable-weak? $wht) (eq-hashtable-weak? $wht) (hashtable-mutable? $wht) (hashtable? $imht) (eq-hashtable? $imht) (hashtable-weak? $imht) (eq-hashtable-weak? $imht) (not (hashtable-mutable? $imht)) (hashtable? $wht2) (eq-hashtable? $wht2) (hashtable-weak? $wht2) (eq-hashtable-weak? $wht2) (hashtable-mutable? $wht2))) ; eq-hashtable-ref (error? ; wrong argument count (eq-hashtable-ref)) (error? ; wrong argument count (eq-hashtable-ref $wht)) (error? ; wrong argument count (eq-hashtable-ref $wht 'a)) (error? ; wrong argument count (eq-hashtable-ref $wht 'a 'b 'c)) (error? ; not a hashtable (eq-hashtable-ref '(hash . table) 'a 'b)) ; eq-hashtable-contains? (error? ; wrong argument count (eq-hashtable-contains?)) (error? ; wrong argument count (eq-hashtable-contains? $wht)) (error? ; wrong argument count (eq-hashtable-contains? $wht 'a 'b)) (error? ; not a hashtable (eq-hashtable-contains? '(hash . table) 'a)) ; eq-hashtable-set! (error? ; wrong argument count (eq-hashtable-set!)) (error? ; wrong argument count (eq-hashtable-set! $wht)) (error? ; wrong argument count (eq-hashtable-set! $wht 'a)) (error? ; wrong argument count (eq-hashtable-set! $wht 'a 'b 'c)) (error? ; not a hashtable (eq-hashtable-set! '(hash . table) 'a 'b)) (error? ; hashtable not mutable (eq-hashtable-set! $imht 'a 'b)) ; eq-hashtable-update! (error? ; wrong argument count (eq-hashtable-update!)) (error? ; wrong argument count (eq-hashtable-update! $wht)) (error? ; wrong argument count (eq-hashtable-update! $wht 'a values)) (error? ; wrong argument count (eq-hashtable-update! $wht 'a values 'c 'd)) (error? ; not a hashtable (eq-hashtable-update! '(hash . table) 'a values 'b)) (error? ; hashtable not mutable (eq-hashtable-update! $imht 'a values 'b)) (error? ; not a procedure (eq-hashtable-update! $wht 'a "not a procedure" 'b)) ; eq-hashtable-delete! (error? ; wrong argument count (eq-hashtable-delete!)) (error? ; wrong argument count (eq-hashtable-delete! $wht)) (error? ; wrong argument count (eq-hashtable-delete! $wht 'a 'b)) (error? ; not a hashtable (eq-hashtable-delete! '(hash . table) 'a)) (error? ; hashtable not mutable (eq-hashtable-delete! $imht 'a)) ; eq-hashtable-cell (error? ; wrong argument count (eq-hashtable-cell)) (error? ; wrong argument count (eq-hashtable-cell $wht)) (error? ; wrong argument count (eq-hashtable-cell $wht 'a)) (error? ; wrong argument count (eq-hashtable-cell $wht 'a 'b 'c)) (error? ; not a hashtable (eq-hashtable-cell '(hash . table) 'a 'b)) ; eq-hashtable-weak? (error? ; wrong argument count (eq-hashtable-weak?)) (error? ; wrong argument count (eq-hashtable-weak? $ht 3)) (error? ; not a hashtable (eq-hashtable-weak? '(hash . table))) ) (mat symbol-hashtable-arguments (begin (define $symht (make-hashtable symbol-hash eq? 50)) (define $imsymht (hashtable-copy $symht)) #t) ; symbol-hashtable-ref (error? ; wrong argument count (symbol-hashtable-ref)) (error? ; wrong argument count (symbol-hashtable-ref $symht)) (error? ; wrong argument count (symbol-hashtable-ref $symht 'a)) (error? ; wrong argument count (symbol-hashtable-ref $symht 'a 'b 'c)) (error? ; not a hashtable (symbol-hashtable-ref '(hash . table) 'a 'b)) (error? ; not a symbol hashtable (symbol-hashtable-ref $ht 'a 'b)) (error? ; not a symbol (symbol-hashtable-ref $symht '(a) 'b)) (error? ; not a symbol (hashtable-ref $symht '(a) 'b)) ; symbol-hashtable-contains? (error? ; wrong argument count (symbol-hashtable-contains?)) (error? ; wrong argument count (symbol-hashtable-contains? $symht)) (error? ; wrong argument count (symbol-hashtable-contains? $symht 'a 'b)) (error? ; not a hashtable (symbol-hashtable-contains? '(hash . table) 'a)) (error? ; not a symbol hashtable (symbol-hashtable-contains? $ht 'a)) (error? ; not a symbol (symbol-hashtable-contains? $symht '(a))) (error? ; not a symbol (hashtable-contains? $symht '(a))) ; symbol-hashtable-set! (error? ; wrong argument count (symbol-hashtable-set!)) (error? ; wrong argument count (symbol-hashtable-set! $symht)) (error? ; wrong argument count (symbol-hashtable-set! $symht 'a)) (error? ; wrong argument count (symbol-hashtable-set! $symht 'a 'b 'c)) (error? ; not a hashtable (symbol-hashtable-set! '(hash . table) 'a 'b)) (error? ; not a symbol hashtable (symbol-hashtable-set! $ht 'a 'b)) (error? ; not a symbol (symbol-hashtable-set! $symht '(a) 'b)) (error? ; not a symbol (hashtable-set! $symht '(a) 'b)) (error? ; hashtable not mutable (symbol-hashtable-set! $imsymht 'a 'b)) ; symbol-hashtable-update! (error? ; wrong argument count (symbol-hashtable-update!)) (error? ; wrong argument count (symbol-hashtable-update! $symht)) (error? ; wrong argument count (symbol-hashtable-update! $symht 'a values)) (error? ; wrong argument count (symbol-hashtable-update! $symht 'a values 'c 'd)) (error? ; not a hashtable (symbol-hashtable-update! '(hash . table) 'a values 'b)) (error? ; not a symbol hashtable (symbol-hashtable-update! $ht 'a values 'b)) (error? ; not a symbol (symbol-hashtable-update! $symht '(a) values 'b)) (error? ; not a symbol (hashtable-update! $symht '(a) values 'b)) (error? ; hashtable not mutable (symbol-hashtable-update! $imsymht 'a values 'b)) (error? ; not a procedure (symbol-hashtable-update! $symht 'a "not a procedure" 'b)) ; symbol-hashtable-delete! (error? ; wrong argument count (symbol-hashtable-delete!)) (error? ; wrong argument count (symbol-hashtable-delete! $symht)) (error? ; wrong argument count (symbol-hashtable-delete! $symht 'a 'b)) (error? ; not a hashtable (symbol-hashtable-delete! '(hash . table) 'a)) (error? ; not a symbol hashtable (symbol-hashtable-delete! $ht 'a)) (error? ; not a symbol (symbol-hashtable-delete! $symht '(a))) (error? ; not a symbol (hashtable-delete! $symht '(a))) (error? ; hashtable not mutable (symbol-hashtable-delete! $imsymht 'a)) ; symbol-hashtable-cell (error? ; wrong argument count (symbol-hashtable-cell)) (error? ; wrong argument count (symbol-hashtable-cell $symht)) (error? ; wrong argument count (symbol-hashtable-cell $symht 'a)) (error? ; wrong argument count (symbol-hashtable-cell $symht 'a 'b 'c)) (error? ; not a hashtable (symbol-hashtable-cell '(hash . table) 'a 'b)) (error? ; not a symbol hashtable (symbol-hashtable-cell $ht 'a 'b)) (error? ; not a symbol (symbol-hashtable-cell $symht '(a) 'b)) (error? ; not a symbol (hashtable-cell $symht '(a) 'b)) ) (mat eqv-hashtable-arguments ; make-weak-eqv-hashtable (error? ; wrong argument count (make-weak-eqv-hashtable 3 #t)) (error? ; invalid size (make-weak-eqv-hashtable -1)) (error? ; invalid size (make-weak-eqv-hashtable #t)) (error? ; invalid size (make-weak-eqv-hashtable #f)) ) (mat nonweak-eq-hashtable (begin (define h (make-eq-hashtable 32)) (and (hashtable? h) (eq-hashtable? h) (hashtable-mutable? h) (not (eq-hashtable-weak? h)) (not (hashtable-weak? h)))) (eq? (hashtable-hash-function h) #f) (eq? (hashtable-equivalence-function h) eq?) (equal? (hashtable-size h) 0) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (eqv? (hashtable-set! h 'a 'aval) (void)) (equal? (list (hashtable-contains? h 'a) (hashtable-contains? h 'b) (hashtable-contains? h 'c)) '(#t #f #f)) (eqv? (hashtable-set! h 'b 'bval) (void)) (equal? (list (hashtable-contains? h 'a) (hashtable-contains? h 'b) (hashtable-contains? h 'c)) '(#t #t #f)) (eqv? (hashtable-set! h 'c 'cval) (void)) (equal? (list (hashtable-contains? h 'a) (hashtable-contains? h 'b) (hashtable-contains? h 'c)) '(#t #t #t)) (equal? (hashtable-size h) 3) (same-elements? (hashtable-keys h) '#(a b c)) (same-elements? (hashtable-values h) '#(bval cval aval)) (equal-entries? (hashtable-entries h) '#(b c a) '#(bval cval aval)) #;(same-elements? (list->vector (hashtable-map h cons)) '#((a . aval) (b . bval) (c . cval))) #;(same-elements? (let ([v (make-vector 3)] [i 0]) (hashtable-for-each h (lambda (key val) (vector-set! v i (cons key val)) (set! i (fx+ i 1)))) v) '#((a . aval) (b . bval) (c . cval))) #;(same-elements? (let ([v (make-vector 3)] [i 0]) (hashtable-for-each-cell h (lambda (a) (vector-set! v i a) (set! i (fx+ i 1)))) v) '#((a . aval) (b . bval) (c . cval))) (equal? (hashtable-ref h 'a 1) 'aval) (equal? (hashtable-ref h 'b #f) 'bval) (equal? (hashtable-ref h 'c 'nope) 'cval) (eqv? (hashtable-delete! h 'b) (void)) (equal? (hashtable-size h) 2) (same-elements? (hashtable-keys h) '#(a c)) (same-elements? (hashtable-values h) '#(aval cval)) (equal-entries? (hashtable-entries h) '#(a c) '#(aval cval)) (begin (define h2 (hashtable-copy h #t)) (and (hashtable? h2) (eq-hashtable? h2) (hashtable-mutable? h2) (not (hashtable-weak? h2)) (not (eq-hashtable-weak? h2)))) (eq? (hashtable-hash-function h2) #f) (eq? (hashtable-equivalence-function h2) eq?) (equal? (hashtable-size h2) 2) (same-elements? (hashtable-keys h2) '#(a c)) (same-elements? (hashtable-values h2) '#(aval cval)) (equal-entries? (hashtable-entries h2) '#(a c) '#(aval cval)) (eqv? (hashtable-clear! h 4) (void)) (equal? (list (hashtable-size h) (hashtable-ref h 'a 1) (hashtable-ref h 'b #f) (hashtable-ref h 'c 'nope)) '(0 1 #f nope)) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (equal? (list (hashtable-size h2) (hashtable-ref h2 'a 1) (hashtable-ref h2 'b #f) (hashtable-ref h2 'c 'nope)) '(2 aval #f cval)) (same-elements? (hashtable-keys h2) '#(a c)) (same-elements? (hashtable-values h2) '#(aval cval)) (equal-entries? (hashtable-entries h2) '#(a c) '#(aval cval)) (eqv? (hashtable-update! h 'q (lambda (x) (+ x 1)) 17) (void)) (equal? (hashtable-ref h 'q #f) 18) (eqv? (hashtable-update! h 'q (lambda (x) (+ x 1)) 17) (void)) (equal? (hashtable-ref h 'q #f) 19) (equal? (hashtable-size h) 1) ; test hashtable-copy when some keys may have moved (let ([t (parameterize ([collect-request-handler void]) (let ([h4a (make-eq-hashtable 32)] [k* (map list (make-list 100))]) (for-each (lambda (x) (hashtable-set! h4a x x)) k*) (collect) ; create copy after collection but before otherwise touching h4a (let ([h4b (hashtable-copy h4a #t)]) (andmap (lambda (k) (eq? (hashtable-ref h4b k #f) k)) k*))))]) (collect) t) ; test for proper shrinkage (eqv? (let ([ht (make-eq-hashtable 32)]) (for-each (lambda (k*) (for-each (lambda (k) (hashtable-delete! ht k)) k*)) (let ([k** (map (lambda (x) (map list (make-list 1000))) (make-list 100))]) (for-each (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*)) k**) k**)) (#%$hashtable-veclen ht)) 32) ) (mat weak-eq-hashtable (begin (define ka (list 'a)) (define kb (list 'b)) (define kc (list 'c)) (define kq (list 'q)) (define ky (list 'y)) (define kz (list 'z)) #t) (begin (define h (make-weak-eq-hashtable 32)) (and (hashtable? h) (eq-hashtable? h) (hashtable-mutable? h) (hashtable-weak? h) (eq-hashtable-weak? h))) (eq? (hashtable-hash-function h) #f) (eq? (hashtable-equivalence-function h) eq?) (equal? (hashtable-size h) 0) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (eqv? (hashtable-set! h ka 'aval) (void)) (equal? (list (hashtable-contains? h ka) (hashtable-contains? h kb) (hashtable-contains? h kc)) '(#t #f #f)) (eqv? (hashtable-set! h kb 'bval) (void)) (equal? (list (hashtable-contains? h ka) (hashtable-contains? h kb) (hashtable-contains? h kc)) '(#t #t #f)) (eqv? (hashtable-set! h kc 'cval) (void)) (equal? (list (hashtable-contains? h ka) (hashtable-contains? h kb) (hashtable-contains? h kc)) '(#t #t #t)) (equal? (hashtable-size h) 3) (same-elements? (hashtable-keys h) '#((a) (b) (c))) (same-elements? (hashtable-values h) '#(bval cval aval)) (equal-entries? (hashtable-entries h) '#((a) (b) (c)) '#(aval bval cval)) #;(same-elements? (list->vector (hashtable-map h cons)) '#(((a) . aval) ((b) . bval) ((c) . cval))) #;(same-elements? (let ([v (make-vector 3)] [i 0]) (hashtable-for-each h (lambda (key val) (vector-set! v i (cons key val)) (set! i (fx+ i 1)))) v) '#(((a) . aval) ((b) . bval) ((c) . cval))) #;(same-elements? (let ([v (make-vector 3)] [i 0]) (hashtable-for-each-cell h (lambda (a) (vector-set! v i a) (set! i (fx+ i 1)))) v) '#(((a) . aval) ((b) . bval) ((c) . cval))) (equal? (hashtable-ref h ka 1) 'aval) (equal? (hashtable-ref h kb #f) 'bval) (equal? (hashtable-ref h kc 'nope) 'cval) (eqv? (hashtable-delete! h kb) (void)) (equal? (hashtable-size h) 2) (same-elements? (hashtable-keys h) '#((a) (c))) (same-elements? (hashtable-values h) '#(aval cval)) (equal-entries? (hashtable-entries h) '#((a) (c)) '#(aval cval)) (begin (define h2 (hashtable-copy h #t)) (and (hashtable? h2) (eq-hashtable? h2) (hashtable-mutable? h2) (eq-hashtable-weak? h2) (hashtable-weak? h2))) (eq? (hashtable-hash-function h2) #f) (eq? (hashtable-equivalence-function h2) eq?) (equal? (hashtable-size h2) 2) (same-elements? (hashtable-keys h2) '#((a) (c))) (same-elements? (hashtable-values h2) '#(aval cval)) (equal-entries? (hashtable-entries h2) '#((a) (c)) '#(aval cval)) (eqv? (hashtable-clear! h 4) (void)) (equal? (list (hashtable-size h) (hashtable-ref h ka 1) (hashtable-ref h kb #f) (hashtable-ref h kc 'nope)) '(0 1 #f nope)) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (equal? (list (hashtable-size h2) (hashtable-ref h2 ka 1) (hashtable-ref h2 kb #f) (hashtable-ref h2 kc 'nope)) '(2 aval #f cval)) (same-elements? (hashtable-keys h2) '#((a) (c))) (same-elements? (hashtable-values h2) '#(aval cval)) (equal-entries? (hashtable-entries h2) '#((a) (c)) '#(aval cval)) (eqv? (hashtable-update! h kq (lambda (x) (+ x 1)) 17) (void)) (equal? (hashtable-ref h kq #f) 18) (eqv? (hashtable-update! h kq (lambda (x) (+ x 1)) 17) (void)) (equal? (hashtable-ref h kq #f) 19) (equal? (hashtable-size h) 1) (same-elements? (hashtable-keys h) '#((q))) (same-elements? (hashtable-values h) '#(19)) (eqv? (begin (set! kq (void)) (collect (collect-maximum-generation)) (hashtable-size h)) 0) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) #;(eqv? (hashtable-map h (lambda args (error #f "oops"))) '()) #;(eqv? (hashtable-for-each h (lambda args (error #f "oops"))) (void)) #;(eqv? (hashtable-for-each-cell h (lambda args (error #f "oops"))) (void)) (equal? (hashtable-ref h ky #f) #f) (eqv? (hashtable-set! h ky 'toad) (void)) (equal? (hashtable-ref h ky #f) 'toad) (equal? (hashtable-ref h kz #f) #f) (eqv? (hashtable-update! h kz list 'frog) (void)) (equal? (hashtable-ref h kz #f) '(frog)) (same-elements? (hashtable-keys h) (vector ky kz)) (same-elements? (hashtable-values h) (vector (hashtable-ref h kz #f) 'toad)) (equal-entries? (hashtable-entries h) (vector kz ky) (vector (hashtable-ref h kz #f) 'toad)) (eqv? (hashtable-ref h '(zippo) 'nil) 'nil) (begin (define h3 (hashtable-copy h2 #f)) (and (hashtable? h3) (eq-hashtable? h3) (not (hashtable-mutable? h3)) (eq-hashtable-weak? h3) (hashtable-weak? h3))) (same-elements? (hashtable-keys h2) '#((a) (c))) (same-elements? (hashtable-keys h3) '#((a) (c))) (same-elements? (hashtable-values h2) '#(aval cval)) (same-elements? (hashtable-values h3) '#(aval cval)) (equal? (begin (set! ka (void)) (collect (collect-maximum-generation)) (list (hashtable-size h2) (hashtable-size h3))) '(1 1)) (same-elements? (hashtable-keys h2) '#((c))) (same-elements? (hashtable-keys h3) '#((c))) (same-elements? (hashtable-values h2) '#(cval)) (same-elements? (hashtable-values h3) '#(cval)) (equal-entries? (hashtable-entries h2) '#((c)) '#(cval)) (equal-entries? (hashtable-entries h3) '#((c)) '#(cval)) (eqv? (begin (set! h3 (void)) (collect (collect-maximum-generation)) (hashtable-size h2)) 1) (same-elements? (hashtable-keys h2) '#((c))) (same-elements? (hashtable-values h2) '#(cval)) (equal-entries? (hashtable-entries h2) '#((c)) '#(cval)) ; test for proper shrinkage (eqv? (let ([ht (make-eq-hashtable 32)]) (for-each (lambda (k*) (for-each (lambda (k) (hashtable-delete! ht k)) k*)) (let ([k** (map (lambda (x) (map list (make-list 1000))) (make-list 100))]) (for-each (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*)) k**) k**)) (#%$hashtable-veclen ht)) 32) ; test for proper shrinkage as objects are bwp'd ; uses delete to trigger final shrinkage (equal? (let* ([ht (make-weak-eq-hashtable 32)] [len (#%$hashtable-veclen ht)]) (hashtable-set! ht 'a 'b) (for-each (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*)) (map (lambda (x) (map list (make-list 1000))) (make-list 100))) (collect (collect-maximum-generation)) (hashtable-delete! ht 'a) (list (hashtable-size ht) (= (#%$hashtable-veclen ht) len))) '(0 #t)) ) (mat eq-hashtable-cell (let () (define-record fribble (x)) (define random-object (lambda (x) (case (random 9) [(0) (cons 'a 'b)] [(1) (vector 'c)] [(2) (string #\a #\b)] [(3) (make-fribble 'q)] [(4) (gensym)] [(5) (open-output-string)] [(6) (fxvector 15 55)] [(7) (lambda () x)] [else (box 'top)]))) (let ([ls1 (let f ([n 10000]) (if (fx= n 0) '() (cons (cons (random-object 4) (random-object 7)) (f (fx- n 1)))))] [ht (make-eq-hashtable)] [wht (make-weak-eq-hashtable)]) (let ([ls2 (map (lambda (a1) (eq-hashtable-cell ht (car a1) (cdr a1))) ls1)] [ls3 (map (lambda (a1) (hashtable-cell wht (car a1) (cdr a1))) ls1)]) (unless (andmap (lambda (a1 a2 a3) (and (eq? (car a1) (car a2)) (eq? (car a2) (car a3)))) ls1 ls2 ls3) (errorf #f "keys are not eq")) (unless (andmap (lambda (a1 a2 a3) (and (eq? (cdr a1) (cdr a2)) (eq? (cdr a2) (cdr a3)))) ls1 ls2 ls3) (errorf #f "values are not eq")) (for-each (lambda (a1) (when (fx< (random 10) 5) (set-car! a1 #f))) ls1) (let loop ([i (min (expt (collect-generation-radix) (collect-maximum-generation)) 1000)]) (unless (fx= i 0) (collect) (unless (andmap (lambda (a2 a3) (eq? (car a2) (car a3))) ls2 ls3) (errorf #f "a2/a3 keys not eq after collection")) (unless (andmap (lambda (a3) (not (bwp-object? (car a3)))) ls3) (errorf #f "keys have been bwp'd")) (loop (fx- i 1)))) (for-each (lambda (a2) (hashtable-delete! ht (car a2)) (set-car! a2 #f)) ls2) (unless (and (equal? (hashtable-keys ht) '#()) (equal? (hashtable-values ht) '#()) (zero? (hashtable-size ht))) (errorf #f "wht has not been cleared out")) (let loop ([i (min (expt (collect-generation-radix) (collect-maximum-generation)) 1000)]) (unless (fx= i 0) (collect) (unless (andmap (lambda (a1 a3) (or (not (car a1)) (eq? (car a1) (car a3)))) ls1 ls3) (errorf #f "a1/a3 keys not eq after collection")) (loop (fx- i 1)))) (for-each (lambda (a1 a3) (unless (or (car a1) (bwp-object? (car a3))) (errorf #f "~s has not been bwp'd I" (car a3)))) ls1 ls3) (for-each (lambda (a1) (set-car! a1 #f)) ls1) (collect (collect-maximum-generation)) (unless (andmap (lambda (a3) (bwp-object? (car a3))) ls3) (errorf #f "keys have not been bwp'd II")) (unless (and (equal? (hashtable-keys wht) '#()) (equal? (hashtable-values wht) '#()) (zero? (hashtable-size ht))) (errorf #f "wht has not been cleared out")))) #t) ) (mat $nonweak-eq-hashtable (begin (define h (make-eq-hashtable 32)) (and (hashtable? h) (eq-hashtable? h) (hashtable-mutable? h) (not (eq-hashtable-weak? h)) (not (hashtable-weak? h)))) (eq? (hashtable-hash-function h) #f) (eq? (hashtable-equivalence-function h) eq?) (equal? (hashtable-size h) 0) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (eqv? (eq-hashtable-set! h 'a 'aval) (void)) (equal? (list (eq-hashtable-contains? h 'a) (eq-hashtable-contains? h 'b) (eq-hashtable-contains? h 'c)) '(#t #f #f)) (eqv? (eq-hashtable-set! h 'b 'bval) (void)) (equal? (list (eq-hashtable-contains? h 'a) (eq-hashtable-contains? h 'b) (eq-hashtable-contains? h 'c)) '(#t #t #f)) (eqv? (eq-hashtable-set! h 'c 'cval) (void)) (equal? (list (eq-hashtable-contains? h 'a) (eq-hashtable-contains? h 'b) (eq-hashtable-contains? h 'c)) '(#t #t #t)) (equal? (hashtable-size h) 3) (same-elements? (hashtable-keys h) '#(a b c)) (same-elements? (hashtable-values h) '#(bval cval aval)) (equal-entries? (hashtable-entries h) '#(b c a) '#(bval cval aval)) (equal? (eq-hashtable-ref h 'a 1) 'aval) (equal? (eq-hashtable-ref h 'b #f) 'bval) (equal? (eq-hashtable-ref h 'c 'nope) 'cval) (eqv? (eq-hashtable-delete! h 'b) (void)) (equal? (hashtable-size h) 2) (same-elements? (hashtable-keys h) '#(a c)) (same-elements? (hashtable-values h) '#(aval cval)) (equal-entries? (hashtable-entries h) '#(a c) '#(aval cval)) (begin (define h2 (hashtable-copy h #t)) (and (hashtable? h2) (eq-hashtable? h2) (hashtable-mutable? h2) (not (eq-hashtable-weak? h2)) (not (hashtable-weak? h2)))) (equal? (hashtable-size h2) 2) (same-elements? (hashtable-keys h2) '#(a c)) (same-elements? (hashtable-values h2) '#(aval cval)) (equal-entries? (hashtable-entries h2) '#(a c) '#(aval cval)) (eqv? (hashtable-clear! h 4) (void)) (equal? (list (hashtable-size h) (eq-hashtable-ref h 'a 1) (eq-hashtable-ref h 'b #f) (eq-hashtable-ref h 'c 'nope)) '(0 1 #f nope)) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (equal? (list (hashtable-size h2) (eq-hashtable-ref h2 'a 1) (eq-hashtable-ref h2 'b #f) (eq-hashtable-ref h2 'c 'nope)) '(2 aval #f cval)) (same-elements? (hashtable-keys h2) '#(a c)) (same-elements? (hashtable-values h2) '#(aval cval)) (equal-entries? (hashtable-entries h2) '#(a c) '#(aval cval)) (eqv? (eq-hashtable-update! h 'q (lambda (x) (+ x 1)) 17) (void)) (equal? (eq-hashtable-ref h 'q #f) 18) (eqv? (eq-hashtable-update! h 'q (lambda (x) (+ x 1)) 17) (void)) (equal? (eq-hashtable-ref h 'q #f) 19) (equal? (hashtable-size h) 1) ; test hashtable-copy when some keys may have moved (let ([t (parameterize ([collect-request-handler void]) (let ([h4a (make-eq-hashtable 32)] [k* (map list (make-list 100))]) (for-each (lambda (x) (eq-hashtable-set! h4a x x)) k*) (collect) ; create copy after collection but before otherwise touching h4a (let ([h4b (hashtable-copy h4a #t)]) (andmap (lambda (k) (eq? (eq-hashtable-ref h4b k #f) k)) k*))))]) (collect) t) ; test for proper shrinkage, etc. (equal? (let* ([ht (make-eq-hashtable)] [minlen (#%$hashtable-veclen ht)]) (define power-of-two? (lambda (n) (fx= (fxbit-count n) 1))) (let f ([i 0]) (unless (fx= i (expt 2 17)) (let ([k (fx* i 2)]) (eq-hashtable-set! ht k i) (f (fx+ i 1)) (assert (eq-hashtable-contains? ht k)) (assert (power-of-two? (#%$hashtable-veclen ht))) (eq-hashtable-delete! ht k)))) (list (hashtable-size ht) (fx= (#%$hashtable-veclen ht) minlen))) '(0 #t)) (equal? (let ([ht (make-eq-hashtable 32)]) (define power-of-two? (lambda (n) (fx= (fxbit-count n) 1))) (let f ([i 0]) (unless (fx= i (expt 2 17)) (let ([k (fx* i 2)]) (eq-hashtable-set! ht k i) (f (fx+ i 1)) (assert (eq-hashtable-contains? ht k)) (assert (power-of-two? (#%$hashtable-veclen ht))) (eq-hashtable-delete! ht k)))) (list (hashtable-size ht) (#%$hashtable-veclen ht))) '(0 32)) ) (mat $weak-eq-hashtable (begin (define ka (list 'a)) (define kb (list 'b)) (define kc (list 'c)) (define kq (list 'q)) (define ky (list 'y)) (define kz (list 'z)) #t) (begin (define h (make-weak-eq-hashtable 32)) (and (hashtable? h) (eq-hashtable? h) (hashtable-mutable? h) (eq-hashtable-weak? h) (hashtable-weak? h))) (eq? (hashtable-hash-function h) #f) (eq? (hashtable-equivalence-function h) eq?) (equal? (hashtable-size h) 0) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (eqv? (eq-hashtable-set! h ka 'aval) (void)) (equal? (list (eq-hashtable-contains? h ka) (eq-hashtable-contains? h kb) (eq-hashtable-contains? h kc)) '(#t #f #f)) (eqv? (eq-hashtable-set! h kb 'bval) (void)) (equal? (list (eq-hashtable-contains? h ka) (eq-hashtable-contains? h kb) (eq-hashtable-contains? h kc)) '(#t #t #f)) (eqv? (eq-hashtable-set! h kc 'cval) (void)) (equal? (list (eq-hashtable-contains? h ka) (eq-hashtable-contains? h kb) (eq-hashtable-contains? h kc)) '(#t #t #t)) (equal? (hashtable-size h) 3) (same-elements? (hashtable-keys h) '#((a) (b) (c))) (same-elements? (hashtable-values h) '#(aval bval cval)) (equal-entries? (hashtable-entries h) '#((a) (b) (c)) '#(aval bval cval)) (equal? (eq-hashtable-ref h ka 1) 'aval) (equal? (eq-hashtable-ref h kb #f) 'bval) (equal? (eq-hashtable-ref h kc 'nope) 'cval) (eqv? (eq-hashtable-delete! h kb) (void)) (equal? (hashtable-size h) 2) (same-elements? (hashtable-keys h) '#((a) (c))) (same-elements? (hashtable-values h) '#(aval cval)) (equal-entries? (hashtable-entries h) '#((a) (c)) '#(aval cval)) (begin (define h2 (hashtable-copy h #t)) (and (hashtable? h2) (eq-hashtable? h2) (hashtable-mutable? h2) (hashtable-weak? h2) (eq-hashtable-weak? h2))) (equal? (hashtable-size h2) 2) (same-elements? (hashtable-keys h2) '#((a) (c))) (same-elements? (hashtable-values h2) '#(aval cval)) (equal-entries? (hashtable-entries h2) '#((a) (c)) '#(aval cval)) (eqv? (hashtable-clear! h 4) (void)) (equal? (list (hashtable-size h) (eq-hashtable-ref h ka 1) (eq-hashtable-ref h kb #f) (eq-hashtable-ref h kc 'nope)) '(0 1 #f nope)) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (equal? (list (hashtable-size h2) (eq-hashtable-ref h2 ka 1) (eq-hashtable-ref h2 kb #f) (eq-hashtable-ref h2 kc 'nope)) '(2 aval #f cval)) (same-elements? (hashtable-keys h2) '#((a) (c))) (same-elements? (hashtable-values h2) '#(aval cval)) (equal-entries? (hashtable-entries h2) '#((a) (c)) '#(aval cval)) (eqv? (eq-hashtable-update! h kq (lambda (x) (+ x 1)) 17) (void)) (equal? (eq-hashtable-ref h kq #f) 18) (eqv? (eq-hashtable-update! h kq (lambda (x) (+ x 1)) 17) (void)) (equal? (eq-hashtable-ref h kq #f) 19) (equal? (hashtable-size h) 1) (same-elements? (hashtable-keys h) '#((q))) (same-elements? (hashtable-values h) '#(19)) (eqv? (begin (set! kq (void)) (collect (collect-maximum-generation)) (hashtable-size h)) 0) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (equal? (eq-hashtable-ref h ky #f) #f) (eqv? (eq-hashtable-set! h ky 'toad) (void)) (equal? (eq-hashtable-ref h ky #f) 'toad) (equal? (eq-hashtable-ref h kz #f) #f) (eqv? (eq-hashtable-update! h kz list 'frog) (void)) (equal? (eq-hashtable-ref h kz #f) '(frog)) (same-elements? (hashtable-keys h) (vector ky kz)) (same-elements? (hashtable-values h) (vector (eq-hashtable-ref h kz #f) 'toad)) (equal-entries? (hashtable-entries h) (vector kz ky) (vector (eq-hashtable-ref h kz #f) 'toad)) (eqv? (eq-hashtable-ref h '(zippo) 'nil) 'nil) (begin (define h3 (hashtable-copy h2 #f)) (and (hashtable? h3) (eq-hashtable? h3) (not (hashtable-mutable? h3)) (eq-hashtable-weak? h3) (hashtable-weak? h3))) (same-elements? (hashtable-keys h2) '#((a) (c))) (same-elements? (hashtable-keys h3) '#((a) (c))) (same-elements? (hashtable-values h2) '#(aval cval)) (same-elements? (hashtable-values h3) '#(aval cval)) (equal? (begin (set! ka (void)) (collect (collect-maximum-generation)) (list (hashtable-size h2) (hashtable-size h3))) '(1 1)) (same-elements? (hashtable-keys h2) '#((c))) (same-elements? (hashtable-keys h3) '#((c))) (same-elements? (hashtable-values h2) '#(cval)) (same-elements? (hashtable-values h3) '#(cval)) (equal-entries? (hashtable-entries h2) '#((c)) '#(cval)) (equal-entries? (hashtable-entries h3) '#((c)) '#(cval)) (eqv? (begin (set! h3 (void)) (collect (collect-maximum-generation)) (hashtable-size h2)) 1) (same-elements? (hashtable-keys h2) '#((c))) (same-elements? (hashtable-values h2) '#(cval)) (equal-entries? (hashtable-entries h2) '#((c)) '#(cval)) ; test for proper shrinkage (eqv? (let ([ht (make-eq-hashtable 32)]) (for-each (lambda (k*) (for-each (lambda (k) (eq-hashtable-delete! ht k)) k*)) (let ([k** (map (lambda (x) (map list (make-list 1000))) (make-list 100))]) (for-each (lambda (k*) (map (lambda (k) (eq-hashtable-set! ht k 75)) k*)) k**) k**)) (#%$hashtable-veclen ht)) 32) ; test for proper shrinkage as objects are bwp'd ; uses delete to trigger final shrinkage (equal? (let* ([ht (make-weak-eq-hashtable 32)] [len (#%$hashtable-veclen ht)]) (eq-hashtable-set! ht 'a 'b) (for-each (lambda (k*) (map (lambda (k) (eq-hashtable-set! ht k 75)) k*)) (map (lambda (x) (map list (make-list 1000))) (make-list 100))) (collect (collect-maximum-generation)) (eq-hashtable-delete! ht 'a) (list (hashtable-size ht) (= (#%$hashtable-veclen ht) len))) '(0 #t)) ) (mat eq-strange (begin (define $ht (make-eq-hashtable)) (define $wht (make-weak-eq-hashtable)) (and (hashtable? $ht) (eq-hashtable? $ht) (hashtable? $wht) (eq-hashtable? $wht))) (eqv? (hashtable-set! $ht #f 75) (void)) (eqv? (hashtable-ref $ht #f 80) 75) (eqv? (hashtable-set! $wht #f 75) (void)) (eqv? (hashtable-ref $wht #f 80) 75) (eqv? (hashtable-set! $ht #!bwp "hello") (void)) (equal? (hashtable-ref $ht #!bwp "goodbye") "hello") (eqv? (hashtable-set! $wht #!bwp "hello") (void)) (and (member (hashtable-ref $wht #!bwp "goodbye") '("hello" "goodbye")) #t) ; make sure that association isn't added before procedure is called (equal? (begin (hashtable-update! $ht 'cupie (lambda (x) (hashtable-ref $ht 'cupie (cons 'barbie x))) 'doll) (hashtable-ref $ht 'cupie 'oops)) '(barbie . doll)) (equal? (begin (hashtable-update! $wht 'cupie (lambda (x) (hashtable-ref $wht 'cupie (cons 'barbie x))) 'doll) (hashtable-ref $wht 'cupie 'oops)) '(barbie . doll)) ) (mat eq-hashtable-stress ; stress tests (let () ; nonweak (define pick (lambda (ls) (list-ref ls (random (length ls))))) (define ht (make-eq-hashtable 4)) (let ([ls (remq '|| (oblist))] [n 50000]) (let f ([i 0] [keep '()] [drop '()]) (if (= i n) (and (= (hashtable-size ht) (- n (length drop))) (andmap (lambda (k) (string=? (symbol->string (hashtable-ref ht k #f)) (cond [(string? k) k] [(pair? k) (car k)] [(vector? k) (vector-ref k 0)]))) keep) (andmap (lambda (k) (eq? (hashtable-ref ht k 'no) 'no)) drop)) (let* ([x (pick ls)] [s (string-copy (symbol->string x))]) (let ([k (case (pick '(string pair vector)) [(string) s] [(pair) (list s)] [(vector) (vector s)])]) (hashtable-set! ht k x) (let ([keep (if (= (modulo i 5) 0) (cons k keep) keep)]) (if (= (modulo i 17) 5) (let ([k (pick keep)]) (hashtable-delete! ht k) (let ([drop (cons k drop)]) (when (= (random 5) 3) (hashtable-delete! ht (pick drop))) (f (+ i 1) (remq k keep) drop))) (f (+ i 1) keep drop))))))))) (let () ; weak (define pick (lambda (ls) (list-ref ls (random (length ls))))) (define ht (make-weak-eq-hashtable 4)) (let ([ls (remq '|| (oblist))] [n 50000]) (let f ([i 0] [keep '()] [drop '()]) (if (= i n) (and (<= (hashtable-size ht) (- n (length drop))) (begin (collect (collect-maximum-generation)) (= (hashtable-size ht) (length keep))) (andmap (lambda (k) (string=? (symbol->string (hashtable-ref ht k #f)) (cond [(string? k) k] [(pair? k) (car k)] [(vector? k) (vector-ref k 0)]))) keep) (andmap (lambda (k) (eq? (hashtable-ref ht k 'no) 'no)) drop)) (let* ([x (pick ls)] [s (string-copy (symbol->string x))]) (let ([k (case (pick '(string pair vector)) [(string) s] [(pair) (list s)] [(vector) (vector s)])]) (hashtable-set! ht k x) (let ([keep (if (= (modulo i 5) 0) (cons k keep) keep)]) (if (= (modulo i 17) 5) (let ([k (pick keep)]) (hashtable-delete! ht k) (let ([drop (cons k drop)]) (when (= (random 5) 3) (hashtable-delete! ht (pick drop))) (f (+ i 1) (remq k keep) drop))) (f (+ i 1) keep drop))))))))) ) (mat nonweak-eqv-hashtable (begin (define h (make-eqv-hashtable 32)) (and (hashtable? h) (not (eq-hashtable? h)) (hashtable-mutable? h) (not (hashtable-weak? h)))) (eq? (hashtable-hash-function h) #f) (eq? (hashtable-equivalence-function h) eqv?) (equal? (hashtable-size h) 0) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (eqv? (hashtable-set! h 'a 'aval) (void)) (equal? (list (hashtable-contains? h 'a) (hashtable-contains? h 3.4) (hashtable-contains? h 'c)) '(#t #f #f)) (eqv? (hashtable-set! h 3.4 'bval) (void)) (equal? (list (hashtable-contains? h 'a) (hashtable-contains? h 3.4) (hashtable-contains? h 'c)) '(#t #t #f)) (eqv? (hashtable-set! h 'c 'cval) (void)) (equal? (list (hashtable-contains? h 'a) (hashtable-contains? h 3.4) (hashtable-contains? h 'c)) '(#t #t #t)) (equal? (hashtable-size h) 3) (same-elements? (hashtable-keys h) '#(a 3.4 c)) (same-elements? (hashtable-values h) '#(bval cval aval)) (equal-entries? (hashtable-entries h) '#(3.4 c a) '#(bval cval aval)) #;(same-elements? (list->vector (hashtable-map h cons)) '#((a . aval) (3.4 . bval) (c . cval))) #;(same-elements? (let ([v (make-vector 3)] [i 0]) (hashtable-for-each h (lambda (key val) (vector-set! v i (cons key val)) (set! i (fx+ i 1)))) v) '#((a . aval) (3.4 . bval) (c . cval))) #;(same-elements? (let ([v (make-vector 3)] [i 0]) (hashtable-for-each-cell h (lambda (a) (vector-set! v i a) (set! i (fx+ i 1)))) v) '#((a . aval) (3.4 . bval) (c . cval))) (equal? (hashtable-ref h 'a 1) 'aval) (equal? (hashtable-ref h 3.4 #f) 'bval) (equal? (hashtable-ref h 'c 'nope) 'cval) (eqv? (hashtable-delete! h 3.4) (void)) (equal? (hashtable-size h) 2) (same-elements? (hashtable-keys h) '#(a c)) (same-elements? (hashtable-values h) '#(aval cval)) (equal-entries? (hashtable-entries h) '#(a c) '#(aval cval)) (begin (define h2 (hashtable-copy h #t)) (and (hashtable? h2) (hashtable-mutable? h2) (not (hashtable-weak? h2)))) (eq? (hashtable-hash-function h2) #f) (eq? (hashtable-equivalence-function h2) eqv?) (equal? (hashtable-size h2) 2) (same-elements? (hashtable-keys h2) '#(a c)) (same-elements? (hashtable-values h2) '#(aval cval)) (equal-entries? (hashtable-entries h2) '#(a c) '#(aval cval)) (eqv? (hashtable-clear! h 4) (void)) (equal? (list (hashtable-size h) (hashtable-ref h 'a 1) (hashtable-ref h 3.4 #f) (hashtable-ref h 'c 'nope)) '(0 1 #f nope)) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (equal? (list (hashtable-size h2) (hashtable-ref h2 'a 1) (hashtable-ref h2 3.4 #f) (hashtable-ref h2 'c 'nope)) '(2 aval #f cval)) (same-elements? (hashtable-keys h2) '#(a c)) (same-elements? (hashtable-values h2) '#(aval cval)) (equal-entries? (hashtable-entries h2) '#(a c) '#(aval cval)) (eqv? (hashtable-update! h 'q (lambda (x) (+ x 1)) 17) (void)) (equal? (hashtable-ref h 'q #f) 18) (eqv? (hashtable-update! h 'q (lambda (x) (+ x 1)) 17) (void)) (equal? (hashtable-ref h 'q #f) 19) (equal? (hashtable-size h) 1) ; test hashtable-copy when some keys may have moved (let ([t (parameterize ([collect-request-handler void]) (let ([h4a (make-eqv-hashtable 32)] [k* (map list (make-list 100))]) (for-each (lambda (x) (hashtable-set! h4a x x)) k*) (collect) ; create copy after collection but before otherwise touching h4a (let ([h4b (hashtable-copy h4a #t)]) (andmap (lambda (k) (eqv? (hashtable-ref h4b k #f) k)) k*))))]) (collect) t) ; test for proper shrinkage (equal? (let ([ht (make-eqv-hashtable 32)]) (for-each (lambda (k*) (for-each (lambda (k) (hashtable-delete! ht k)) k*)) (let ([k** (map (lambda (x) (map list (make-list 1000))) (make-list 100))]) (for-each (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*)) k**) k**)) (call-with-values (lambda () (#%$hashtable-veclen ht)) cons)) '(32 . 32)) ) (mat weak-eqv-hashtable (begin (define ka (list 'a)) (define kb (list 'b)) (define kc (list 'c)) (define kq (list 'q)) (define ky (list 'y)) (define kz (list 'z)) (define km -5.75) (define kn 17) (define ko (+ (most-positive-fixnum) 5)) #t) (begin (define h (make-weak-eqv-hashtable 32)) (and (hashtable? h) (not (eq-hashtable? h)) (hashtable-mutable? h) (hashtable-weak? h))) (eq? (hashtable-hash-function h) #f) (eq? (hashtable-equivalence-function h) eqv?) (equal? (hashtable-size h) 0) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (eqv? (hashtable-set! h ka 'aval) (void)) (equal? (list (hashtable-contains? h ka) (hashtable-contains? h kb) (hashtable-contains? h kc) (hashtable-contains? h km) (hashtable-contains? h kn) (hashtable-contains? h ko)) '(#t #f #f #f #f #f)) (eqv? (hashtable-set! h kb 'bval) (void)) (equal? (list (hashtable-contains? h ka) (hashtable-contains? h kb) (hashtable-contains? h kc) (hashtable-contains? h km) (hashtable-contains? h kn) (hashtable-contains? h ko)) '(#t #t #f #f #f #f)) (eqv? (hashtable-set! h kc 'cval) (void)) (equal? (list (hashtable-contains? h ka) (hashtable-contains? h kb) (hashtable-contains? h kc) (hashtable-contains? h km) (hashtable-contains? h kn) (hashtable-contains? h ko)) '(#t #t #t #f #f #f)) (eqv? (hashtable-set! h km 'mval) (void)) (equal? (list (hashtable-contains? h ka) (hashtable-contains? h kb) (hashtable-contains? h kc) (hashtable-contains? h km) (hashtable-contains? h kn) (hashtable-contains? h ko)) '(#t #t #t #t #f #f)) (eqv? (hashtable-set! h kn 'nval) (void)) (equal? (list (hashtable-contains? h ka) (hashtable-contains? h kb) (hashtable-contains? h kc) (hashtable-contains? h km) (hashtable-contains? h kn) (hashtable-contains? h ko)) '(#t #t #t #t #t #f)) (eqv? (hashtable-set! h ko 'oval) (void)) (equal? (list (hashtable-contains? h ka) (hashtable-contains? h kb) (hashtable-contains? h kc) (hashtable-contains? h km) (hashtable-contains? h kn) (hashtable-contains? h ko)) '(#t #t #t #t #t #t)) (equal? (hashtable-size h) 6) (same-elements? (hashtable-keys h) `#((a) (b) (c) -5.75 17 ,ko)) (same-elements? (hashtable-values h) '#(aval bval cval mval nval oval)) (equal-entries? (hashtable-entries h) `#((a) (b) (c) -5.75 17 ,ko) '#(aval bval cval mval nval oval)) #;(same-elements? (list->vector (hashtable-map h cons)) `#(((a) . aval) ((b) . bval) ((c) . cval) (-5.75 . mval) (17 . nval) (,ko . oval))) #;(same-elements? (let ([v (make-vector 6)] [i 0]) (hashtable-for-each h (lambda (key val) (vector-set! v i (cons key val)) (set! i (fx+ i 1)))) v) `#(((a) . aval) ((b) . bval) ((c) . cval) (-5.75 . mval) (17 . nval) (,ko . oval))) #;(same-elements? (let ([v (make-vector 6)] [i 0]) (hashtable-for-each-cell h (lambda (a) (vector-set! v i a) (set! i (fx+ i 1)))) v) `#(((a) . aval) ((b) . bval) ((c) . cval) (-5.75 . mval) (17 . nval) (,ko . oval))) (eq? (hashtable-ref h ka 1) 'aval) (eq? (hashtable-ref h kb #f) 'bval) (eq? (hashtable-ref h kc 'nope) 'cval) (eq? (hashtable-ref h (+ 2 -7.75) 'ugh) 'mval) (eq? (hashtable-ref h (/ 34 2) 'ugh) 'nval) (eq? (hashtable-ref h (+ (most-positive-fixnum) 7 -2) 'ugh) 'oval) (eqv? (hashtable-delete! h kb) (void)) (equal? (hashtable-size h) 5) (same-elements? (hashtable-keys h) `#((a) (c) -5.75 17 ,ko)) (same-elements? (hashtable-values h) '#(aval cval mval nval oval)) (equal-entries? (hashtable-entries h) `#((a) (c) -5.75 17 ,ko) '#(aval cval mval nval oval)) (begin (define h2 (hashtable-copy h #t)) (and (hashtable? h2) (hashtable-mutable? h2) (hashtable-weak? h2))) (eq? (hashtable-hash-function h2) #f) (eq? (hashtable-equivalence-function h2) eqv?) (equal? (hashtable-size h2) 5) (same-elements? (hashtable-keys h) `#((a) (c) -5.75 17 ,ko)) (same-elements? (hashtable-values h) '#(aval cval mval nval oval)) (equal-entries? (hashtable-entries h) `#((a) (c) -5.75 17 ,ko) '#(aval cval mval nval oval)) (eqv? (hashtable-clear! h 4) (void)) (equal? (list (hashtable-size h) (hashtable-ref h ka 1) (hashtable-ref h kb #f) (hashtable-ref h kc 'nope) (hashtable-ref h km 'nope) (hashtable-ref h kn 'nope) (hashtable-ref h ko 'nope)) '(0 1 #f nope nope nope nope)) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (equal? (list (hashtable-size h2) (hashtable-ref h2 ka 1) (hashtable-ref h2 kb #f) (hashtable-ref h2 kc 'nope) (hashtable-ref h2 (- (+ km 1) 1) 'nope) (hashtable-ref h2 (- (+ kn 1) 1) 'nope) (hashtable-ref h2 (- (+ ko 1) 1) 'nope)) '(5 aval #f cval mval nval oval)) (same-elements? (hashtable-keys h2) `#((a) (c) -5.75 17 ,ko)) (same-elements? (hashtable-values h2) '#(aval cval mval nval oval)) (equal-entries? (hashtable-entries h2) `#((a) (c) -5.75 17 ,ko) '#(aval cval mval nval oval)) (eqv? (hashtable-update! h kq (lambda (x) (+ x 1)) 17) (void)) (equal? (hashtable-ref h kq #f) 18) (eqv? (hashtable-update! h kq (lambda (x) (+ x 1)) 17) (void)) (equal? (hashtable-ref h kq #f) 19) (equal? (hashtable-size h) 1) (same-elements? (hashtable-keys h) '#((q))) (eqv? (begin (set! kq (void)) (collect (collect-maximum-generation)) (hashtable-size h)) 0) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (equal? (hashtable-ref h ky #f) #f) (eqv? (hashtable-set! h ky 'toad) (void)) (equal? (hashtable-ref h ky #f) 'toad) (equal? (hashtable-ref h kz #f) #f) (eqv? (hashtable-update! h kz list 'frog) (void)) (equal? (hashtable-ref h kz #f) '(frog)) (same-elements? (hashtable-keys h) (vector ky kz)) (same-elements? (hashtable-values h) (vector (hashtable-ref h kz #f) 'toad)) (equal-entries? (hashtable-entries h) (vector kz ky) (vector (hashtable-ref h kz #f) 'toad)) (eqv? (hashtable-ref h '(zippo) 'nil) 'nil) (begin (define h3 (hashtable-copy h2 #f)) (and (hashtable? h3) (not (hashtable-mutable? h3)) (hashtable-weak? h3))) (same-elements? (hashtable-keys h2) `#((a) (c) -5.75 17 ,ko)) (same-elements? (hashtable-keys h3) `#((a) (c) -5.75 17 ,ko)) (equal? (begin (set! ka (void)) (set! km (void)) (set! kn (void)) (set! ko (void)) (collect (collect-maximum-generation)) (list (hashtable-size h2) (hashtable-size h3))) '(4 4)) (same-elements? (hashtable-keys h2) `#((c) -5.75 17 ,(+ (most-positive-fixnum) 5))) (same-elements? (hashtable-keys h3) `#((c) -5.75 17 ,(+ (most-positive-fixnum) 5))) (same-elements? (hashtable-values h2) '#(cval mval nval oval)) (same-elements? (hashtable-values h3) '#(cval mval nval oval)) (equal-entries? (hashtable-entries h2) `#((c) -5.75 17 ,(+ (most-positive-fixnum) 5)) '#(cval mval nval oval)) (equal-entries? (hashtable-entries h3) `#((c) -5.75 17 ,(+ (most-positive-fixnum) 5)) '#(cval mval nval oval)) (eqv? (begin (set! h3 (void)) (collect (collect-maximum-generation)) (hashtable-size h2)) 4) (same-elements? (hashtable-keys h2) `#((c) -5.75 17 ,(+ (most-positive-fixnum) 5))) (same-elements? (hashtable-values h2) '#(cval mval nval oval)) (equal-entries? (hashtable-entries h2) `#((c) -5.75 17 ,(+ (most-positive-fixnum) 5)) '#(cval mval nval oval)) ; test for proper shrinkage (equal? (let ([ht (make-eqv-hashtable 32)]) (for-each (lambda (k*) (for-each (lambda (k) (hashtable-delete! ht k)) k*)) (let ([k** (map (lambda (x) (map list (make-list 1000))) (make-list 100))]) (for-each (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*)) k**) k**)) (call-with-values (lambda () (#%$hashtable-veclen ht)) cons)) '(32 . 32)) ; test for proper shrinkage as objects are bwp'd ; uses delete to trigger final shrinkage (equal? (let ([ht (make-weak-eqv-hashtable 32)]) (hashtable-set! ht 'a 'b) (for-each (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*)) (map (lambda (x) (map list (make-list 1000))) (make-list 100))) (collect (collect-maximum-generation)) (hashtable-delete! ht 'a) (list (hashtable-size ht) (let-values ([(n1 n2) (#%$hashtable-veclen ht)]) (= n1 n2 32)))) '(0 #t)) ) (mat eqv-hashtable-cell (let () (define-record fribble (x)) (define random-object (lambda (x) (case (random 9) [(0) (cons 'a 3.4)] [(1) (vector 'c)] [(2) (string #\a #\b)] [(3) (make-fribble 'q)] [(4) (gensym)] [(5) (open-output-string)] [(6) (fxvector 15 55)] [(7) (lambda () x)] [else (box 'top)]))) (let ([ls1 (let f ([n 10000]) (if (fx= n 0) '() (cons (cons (random-object 4) (random-object 7)) (f (fx- n 1)))))] [ht (make-eqv-hashtable)] [wht (make-weak-eqv-hashtable)]) (let ([ls2 (map (lambda (a1) (hashtable-cell ht (car a1) (cdr a1))) ls1)] [ls3 (map (lambda (a1) (hashtable-cell wht (car a1) (cdr a1))) ls1)]) (unless (andmap (lambda (a1 a2 a3) (and (eqv? (car a1) (car a2)) (eqv? (car a2) (car a3)))) ls1 ls2 ls3) (errorf #f "keys are not eqv")) (unless (andmap (lambda (a1 a2 a3) (and (eqv? (cdr a1) (cdr a2)) (eqv? (cdr a2) (cdr a3)))) ls1 ls2 ls3) (errorf #f "values are not eqv")) (for-each (lambda (a1) (when (fx< (random 10) 5) (set-car! a1 #f))) ls1) (let loop ([i (min (expt (collect-generation-radix) (collect-maximum-generation)) 1000)]) (unless (fx= i 0) (collect) (unless (andmap (lambda (a2 a3) (eqv? (car a2) (car a3))) ls2 ls3) (errorf #f "a2/a3 keys not eqv after collection")) (unless (andmap (lambda (a3) (not (bwp-object? (car a3)))) ls3) (errorf #f "keys have been bwp'd")) (loop (fx- i 1)))) (for-each (lambda (a2) (hashtable-delete! ht (car a2)) (set-car! a2 #f)) ls2) (unless (and (equal? (hashtable-keys ht) '#()) (equal? (hashtable-values ht) '#()) (zero? (hashtable-size ht))) (errorf #f "wht has not been cleared out")) (let loop ([i (min (expt (collect-generation-radix) (collect-maximum-generation)) 1000)]) (unless (fx= i 0) (collect) (unless (andmap (lambda (a1 a3) (or (not (car a1)) (eqv? (car a1) (car a3)))) ls1 ls3) (errorf #f "a1/a3 keys not eqv after collection")) (loop (fx- i 1)))) (for-each (lambda (a1 a3) (unless (or (car a1) (bwp-object? (car a3))) (errorf #f "~s has not been bwp'd I" (car a3)))) ls1 ls3) (for-each (lambda (a1) (set-car! a1 #f)) ls1) (collect (collect-maximum-generation)) (unless (andmap (lambda (a3) (bwp-object? (car a3))) ls3) (errorf #f "keys have not been bwp'd II")) (unless (and (equal? (hashtable-keys wht) '#()) (equal? (hashtable-values ht) '#()) (zero? (hashtable-size ht))) (errorf #f "wht has not been cleared out")))) #t) ) (mat eqv-strange (begin (define $ht (make-eqv-hashtable)) (define $wht (make-weak-eqv-hashtable)) (and (hashtable? $ht) (hashtable? $wht))) (eqv? (hashtable-set! $ht #f 75) (void)) (eqv? (hashtable-ref $ht #f 80) 75) (eqv? (hashtable-set! $wht #f 75) (void)) (eqv? (hashtable-ref $wht #f 80) 75) (eqv? (hashtable-set! $ht #!bwp "hello") (void)) (equal? (hashtable-ref $ht #!bwp "goodbye") "hello") (eqv? (hashtable-set! $wht #!bwp "hello") (void)) (and (member (hashtable-ref $wht #!bwp "goodbye") '("hello" "goodbye")) #t) ; make sure that association isn't added before procedure is called (equal? (begin (hashtable-update! $ht 'cupie (lambda (x) (hashtable-ref $ht 'cupie (cons 'barbie x))) 'doll) (hashtable-ref $ht 'cupie 'oops)) '(barbie . doll)) (equal? (begin (hashtable-update! $wht 'cupie (lambda (x) (hashtable-ref $wht 'cupie (cons 'barbie x))) 'doll) (hashtable-ref $wht 'cupie 'oops)) '(barbie . doll)) ) (mat eqv-hashtable-stress ; stress tests (let () ; nonweak (define pick (lambda (ls) (list-ref ls (random (length ls))))) (define ht (make-eqv-hashtable 4)) (let ([ls (remq '|| (oblist))] [n 50000]) (let f ([i 0] [keep '()] [drop '()]) (if (= i n) (and (= (hashtable-size ht) (- n (length drop))) (andmap (lambda (k) (string=? (symbol->string (hashtable-ref ht k #f)) (cond [(string? k) k] [(pair? k) (car k)] [(vector? k) (vector-ref k 0)]))) keep) (andmap (lambda (k) (eqv? (hashtable-ref ht k 'no) 'no)) drop)) (let* ([x (pick ls)] [s (string-copy (symbol->string x))]) (let ([k (case (pick '(string pair vector)) [(string) s] [(pair) (list s)] [(vector) (vector s)])]) (hashtable-set! ht k x) (let ([keep (if (= (modulo i 5) 0) (cons k keep) keep)]) (if (= (modulo i 17) 5) (let ([k (pick keep)]) (hashtable-delete! ht k) (let ([drop (cons k drop)]) (when (= (random 5) 3) (hashtable-delete! ht (pick drop))) (f (+ i 1) (remq k keep) drop))) (f (+ i 1) keep drop))))))))) (let () ; weak (define pick (lambda (ls) (list-ref ls (random (length ls))))) (define ht (make-weak-eqv-hashtable 4)) (let ([ls (remq '|| (oblist))] [n 50000]) (let f ([i 0] [keep '()] [drop '()]) (if (= i n) (and (<= (hashtable-size ht) (- n (length drop))) (begin (collect (collect-maximum-generation)) (= (hashtable-size ht) (length keep))) (andmap (lambda (k) (string=? (symbol->string (hashtable-ref ht k #f)) (cond [(string? k) k] [(pair? k) (car k)] [(vector? k) (vector-ref k 0)]))) keep) (andmap (lambda (k) (eqv? (hashtable-ref ht k 'no) 'no)) drop)) (let* ([x (pick ls)] [s (string-copy (symbol->string x))]) (let ([k (case (pick '(string pair vector)) [(string) s] [(pair) (list s)] [(vector) (vector s)])]) (hashtable-set! ht k x) (let ([keep (if (= (modulo i 5) 0) (cons k keep) keep)]) (if (= (modulo i 17) 5) (let ([k (pick keep)]) (hashtable-delete! ht k) (let ([drop (cons k drop)]) (when (= (random 5) 3) (hashtable-delete! ht (pick drop))) (f (+ i 1) (remq k keep) drop))) (f (+ i 1) keep drop))))))))) ) (mat symbol-hashtable (let ([ht (make-hashtable symbol-hash eq?)]) (and (symbol-hashtable? ht) (eq? (hashtable-equivalence-function ht) eq?))) (let ([ht (make-hashtable symbol-hash eqv?)]) (and (symbol-hashtable? ht) (eq? (hashtable-equivalence-function ht) eqv?))) (let ([ht (make-hashtable symbol-hash equal?)]) (and (symbol-hashtable? ht) (eq? (hashtable-equivalence-function ht) equal?))) (let ([ht (make-hashtable symbol-hash symbol=?)]) (and (symbol-hashtable? ht) (eq? (hashtable-equivalence-function ht) symbol=?))) (let ([ht (make-hashtable symbol-hash eq? 17)]) (and (symbol-hashtable? ht) (eq? (hashtable-equivalence-function ht) eq?))) (let ([ht (make-hashtable symbol-hash eqv? 17)]) (and (symbol-hashtable? ht) (eq? (hashtable-equivalence-function ht) eqv?))) (let ([ht (make-hashtable symbol-hash equal? 17)]) (and (symbol-hashtable? ht) (eq? (hashtable-equivalence-function ht) equal?))) (let ([ht (make-hashtable symbol-hash symbol=? 17)]) (and (symbol-hashtable? ht) (eq? (hashtable-equivalence-function ht) symbol=?))) (begin (define h (make-hashtable symbol-hash eq? 32)) (and (hashtable? h) (symbol-hashtable? h) (hashtable-mutable? h) (not (eq-hashtable? h)) (not (hashtable-weak? h)))) (eq? (hashtable-hash-function h) symbol-hash) (eq? (hashtable-equivalence-function h) eq?) (equal? (hashtable-size h) 0) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (eqv? (hashtable-set! h 'a 'aval) (void)) (equal? (list (hashtable-contains? h 'a) (hashtable-contains? h 'b) (hashtable-contains? h 'c)) '(#t #f #f)) (eqv? (hashtable-set! h 'b 'bval) (void)) (equal? (list (hashtable-contains? h 'a) (hashtable-contains? h 'b) (hashtable-contains? h 'c)) '(#t #t #f)) (eqv? (hashtable-set! h 'c 'cval) (void)) (equal? (list (hashtable-contains? h 'a) (hashtable-contains? h 'b) (hashtable-contains? h 'c)) '(#t #t #t)) (equal? (hashtable-size h) 3) (same-elements? (hashtable-keys h) '#(a b c)) (same-elements? (hashtable-values h) '#(bval cval aval)) (equal-entries? (hashtable-entries h) '#(b c a) '#(bval cval aval)) #;(same-elements? (list->vector (hashtable-map h cons)) '#((a . aval) (b . bval) (c . cval))) #;(same-elements? (let ([v (make-vector 3)] [i 0]) (hashtable-for-each h (lambda (key val) (vector-set! v i (cons key val)) (set! i (fx+ i 1)))) v) '#((a . aval) (b . bval) (c . cval))) #;(same-elements? (let ([v (make-vector 3)] [i 0]) (hashtable-for-each-cell h (lambda (a) (vector-set! v i a) (set! i (fx+ i 1)))) v) '#((a . aval) (b . bval) (c . cval))) (equal? (hashtable-ref h 'a 1) 'aval) (equal? (hashtable-ref h 'b #f) 'bval) (equal? (hashtable-ref h 'c 'nope) 'cval) (eqv? (hashtable-delete! h 'b) (void)) (equal? (hashtable-size h) 2) (same-elements? (hashtable-keys h) '#(a c)) (same-elements? (hashtable-values h) '#(aval cval)) (equal-entries? (hashtable-entries h) '#(a c) '#(aval cval)) (begin (define h2 (hashtable-copy h #t)) (and (hashtable? h2) (symbol-hashtable? h2) (hashtable-mutable? h2) (not (hashtable-weak? h2)) (not (eq-hashtable? h2)))) (eq? (hashtable-hash-function h2) symbol-hash) (eq? (hashtable-equivalence-function h2) eq?) (equal? (hashtable-size h2) 2) (same-elements? (hashtable-keys h2) '#(a c)) (same-elements? (hashtable-values h2) '#(aval cval)) (equal-entries? (hashtable-entries h2) '#(a c) '#(aval cval)) (eqv? (hashtable-clear! h 4) (void)) (equal? (list (hashtable-size h) (hashtable-ref h 'a 1) (hashtable-ref h 'b #f) (hashtable-ref h 'c 'nope)) '(0 1 #f nope)) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (equal? (list (hashtable-size h2) (hashtable-ref h2 'a 1) (hashtable-ref h2 'b #f) (hashtable-ref h2 'c 'nope)) '(2 aval #f cval)) (same-elements? (hashtable-keys h2) '#(a c)) (same-elements? (hashtable-values h2) '#(aval cval)) (equal-entries? (hashtable-entries h2) '#(a c) '#(aval cval)) (eqv? (hashtable-update! h 'q (lambda (x) (+ x 1)) 17) (void)) (equal? (hashtable-ref h 'q #f) 18) (eqv? (hashtable-update! h 'q (lambda (x) (+ x 1)) 17) (void)) (equal? (hashtable-ref h 'q #f) 19) (equal? (hashtable-size h) 1) ; test hashtable-copy when some keys may have moved ; symbol hashes don't change, but keeping test adapted from eq-hashtable mats anyway (let ([t (parameterize ([collect-request-handler void]) (let ([h4a (make-hashtable symbol-hash eqv? 32)] [k* (list-head (oblist) 100)]) (for-each (lambda (x) (hashtable-set! h4a x x)) k*) (collect) ; create copy after collection but before otherwise touching h4a (let ([h4b (hashtable-copy h4a #t)]) (andmap (lambda (k) (eq? (hashtable-ref h4b k #f) k)) k*))))]) (collect) t) ; test for proper shrinkage (eqv? (let ([ht (make-hashtable symbol-hash equal? 32)]) (for-each (lambda (k*) (for-each (lambda (k) (hashtable-delete! ht k)) k*)) (let ([k** (map (lambda (x) (list-head (oblist) 1000)) (make-list 100))]) (for-each (lambda (k*) (map (lambda (k) (hashtable-set! ht k 75)) k*)) k**) k**)) (#%$hashtable-veclen ht)) 32) ) (mat $symbol-hashtable (begin (define h (make-hashtable symbol-hash eq? 32)) (and (hashtable? h) (symbol-hashtable? h) (hashtable-mutable? h) (not (eq-hashtable? h)) (not (hashtable-weak? h)))) (eq? (hashtable-hash-function h) symbol-hash) (eq? (hashtable-equivalence-function h) eq?) (equal? (hashtable-size h) 0) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (eqv? (symbol-hashtable-set! h 'a 'aval) (void)) (equal? (list (symbol-hashtable-contains? h 'a) (symbol-hashtable-contains? h 'b) (symbol-hashtable-contains? h 'c)) '(#t #f #f)) (eqv? (symbol-hashtable-set! h 'b 'bval) (void)) (equal? (list (symbol-hashtable-contains? h 'a) (symbol-hashtable-contains? h 'b) (symbol-hashtable-contains? h 'c)) '(#t #t #f)) (eqv? (symbol-hashtable-set! h 'c 'cval) (void)) (equal? (list (symbol-hashtable-contains? h 'a) (symbol-hashtable-contains? h 'b) (symbol-hashtable-contains? h 'c)) '(#t #t #t)) (equal? (hashtable-size h) 3) (same-elements? (hashtable-keys h) '#(a b c)) (same-elements? (hashtable-values h) '#(bval cval aval)) (equal-entries? (hashtable-entries h) '#(b c a) '#(bval cval aval)) #;(same-elements? (list->vector (hashtable-map h cons)) '#((a . aval) (b . bval) (c . cval))) #;(same-elements? (let ([v (make-vector 3)] [i 0]) (hashtable-for-each h (lambda (key val) (vector-set! v i (cons key val)) (set! i (fx+ i 1)))) v) '#((a . aval) (b . bval) (c . cval))) #;(same-elements? (let ([v (make-vector 3)] [i 0]) (hashtable-for-each-cell h (lambda (a) (vector-set! v i a) (set! i (fx+ i 1)))) v) '#((a . aval) (b . bval) (c . cval))) (equal? (symbol-hashtable-ref h 'a 1) 'aval) (equal? (symbol-hashtable-ref h 'b #f) 'bval) (equal? (symbol-hashtable-ref h 'c 'nope) 'cval) (eqv? (symbol-hashtable-delete! h 'b) (void)) (equal? (hashtable-size h) 2) (same-elements? (hashtable-keys h) '#(a c)) (same-elements? (hashtable-values h) '#(aval cval)) (equal-entries? (hashtable-entries h) '#(a c) '#(aval cval)) (begin (define h2 (hashtable-copy h #t)) (and (hashtable? h2) (symbol-hashtable? h2) (hashtable-mutable? h2) (not (hashtable-weak? h2)) (not (eq-hashtable? h2)))) (eq? (hashtable-hash-function h2) symbol-hash) (eq? (hashtable-equivalence-function h2) eq?) (equal? (hashtable-size h2) 2) (same-elements? (hashtable-keys h2) '#(a c)) (same-elements? (hashtable-values h2) '#(aval cval)) (equal-entries? (hashtable-entries h2) '#(a c) '#(aval cval)) (eqv? (hashtable-clear! h 4) (void)) (equal? (list (hashtable-size h) (symbol-hashtable-ref h 'a 1) (symbol-hashtable-ref h 'b #f) (symbol-hashtable-ref h 'c 'nope)) '(0 1 #f nope)) (same-elements? (hashtable-keys h) '#()) (same-elements? (hashtable-values h) '#()) (equal-entries? (hashtable-entries h) '#() '#()) (equal? (list (hashtable-size h2) (symbol-hashtable-ref h2 'a 1) (symbol-hashtable-ref h2 'b #f) (symbol-hashtable-ref h2 'c 'nope)) '(2 aval #f cval)) (same-elements? (hashtable-keys h2) '#(a c)) (same-elements? (hashtable-values h2) '#(aval cval)) (equal-entries? (hashtable-entries h2) '#(a c) '#(aval cval)) (eqv? (symbol-hashtable-update! h 'q (lambda (x) (+ x 1)) 17) (void)) (equal? (symbol-hashtable-ref h 'q #f) 18) (eqv? (symbol-hashtable-update! h 'q (lambda (x) (+ x 1)) 17) (void)) (equal? (symbol-hashtable-ref h 'q #f) 19) (equal? (hashtable-size h) 1) (let ([g (gensym)] [s "feisty"]) (let ([a (symbol-hashtable-cell h g s)]) (and (pair? a) (eq? (car a) g) (eq? (cdr a) s) (begin (hashtable-set! h g 'feisty) (eq? (cdr a) 'feisty)) (begin (set-cdr! a (list "feisty")) (equal? (hashtable-ref h g #f) '("feisty")))))) ; test hashtable-copy when some keys may have moved ; symbol hashes don't change, but keeping test adapted from eq-hashtable mats anyway (let ([t (parameterize ([collect-request-handler void]) (let ([h4a (make-hashtable symbol-hash eqv? 32)] [k* (list-head (oblist) 100)]) (for-each (lambda (x) (symbol-hashtable-set! h4a x x)) k*) (collect) ; create copy after collection but before otherwise touching h4a (let ([h4b (hashtable-copy h4a #t)]) (andmap (lambda (k) (eq? (symbol-hashtable-ref h4b k #f) k)) k*))))]) (collect) t) ; test for proper shrinkage (eqv? (let ([ht (make-hashtable symbol-hash equal? 32)]) (for-each (lambda (k*) (for-each (lambda (k) (symbol-hashtable-delete! ht k)) k*)) (let ([k** (map (lambda (x) (list-head (oblist) 1000)) (make-list 100))]) (for-each (lambda (k*) (map (lambda (k) (symbol-hashtable-set! ht k 75)) k*)) k**) k**)) (#%$hashtable-veclen ht)) 32) ) (mat symbol-hashtable-stress ; stress tests (let () ; nonweak (define pick (lambda (ls) (list-ref ls (random (length ls))))) (define ht (make-hashtable symbol-hash eq? 4)) (let ([ls (remq '|| (oblist))] [n 50000]) (let f ([i 0] [keep '()] [drop '()]) (if (= i n) (and (= (hashtable-size ht) (- n (length drop))) (andmap (lambda (k) (string=? (symbol->string (hashtable-ref ht k #f)) (symbol->string k))) keep) (andmap (lambda (k) (eq? (hashtable-ref ht k 'no) 'no)) drop)) (let* ([x (pick ls)] [s (string-copy (symbol->string x))]) (let ([k (gensym s)]) (hashtable-set! ht k x) (let ([keep (if (= (modulo i 5) 0) (cons k keep) keep)]) (if (= (modulo i 17) 5) (let ([k (pick keep)]) (hashtable-delete! ht k) (let ([drop (cons k drop)]) (when (= (random 5) 3) (hashtable-delete! ht (pick drop))) (f (+ i 1) (remq k keep) drop))) (f (+ i 1) keep drop))))))))) ) (mat generic-hashtable (begin (define $ght-keys1 '#(a b c d e f g)) (define $ght-vals1 '#(1 3 5 7 9 11 13)) (define $ght (make-hashtable equal-hash equal? 8)) (vector-for-each (lambda (x i) (hashtable-set! $ght x i)) $ght-keys1 $ght-vals1) (hashtable? $ght)) (not (eq-hashtable? $ght)) (eq? (hashtable-hash-function $ght) equal-hash) (eq? (hashtable-equivalence-function $ght) equal?) (eq? (hashtable-mutable? $ght) #t) (not (hashtable-weak? $ght)) (eqv? (hashtable-size $ght) (vector-length $ght-keys1)) (eqv? (#%$hashtable-veclen $ght) 8) (same-elements? (hashtable-keys $ght) $ght-keys1) (same-elements? (hashtable-values $ght) $ght-vals1) (equal-entries? (hashtable-entries $ght) $ght-keys1 $ght-vals1) (begin (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)))) (define $ght-vals2 '#(a b c d e f g h i j k l m)) (vector-for-each (lambda (x i) (hashtable-set! $ght x i)) $ght-keys2 $ght-vals2) (eq? (hashtable-size $ght) (+ (vector-length $ght-keys1) (vector-length $ght-keys2)))) (> (#%$hashtable-veclen $ght) 8) (same-elements? (hashtable-keys $ght) ($vector-append $ght-keys1 $ght-keys2)) (same-elements? (hashtable-values $ght) ($vector-append $ght-vals1 $ght-vals2)) (equal-entries? (hashtable-entries $ght) ($vector-append $ght-keys1 $ght-keys2) ($vector-append $ght-vals1 $ght-vals2)) #;(same-elements? (list->vector (hashtable-map $ght cons)) (vector-map cons ($vector-append $ght-keys1 $ght-keys2) ($vector-append $ght-vals1 $ght-vals2))) #;(same-elements? (let ([v (make-vector (+ (vector-length $ght-keys1) (vector-length $ght-keys2)))] [i 0]) (hashtable-for-each $ght (lambda (key val) (vector-set! v i (cons key val)) (set! i (fx+ i 1)))) v) (vector-map cons ($vector-append $ght-keys1 $ght-keys2) ($vector-append $ght-vals1 $ght-vals2))) #;(same-elements? (let ([v (make-vector (+ (vector-length $ght-keys1) (vector-length $ght-keys2)))] [i 0]) (hashtable-for-each-cell $ght (lambda (a) (vector-set! v i a) (set! i (fx+ i 1)))) v) (vector-map cons ($vector-append $ght-keys1 $ght-keys2) ($vector-append $ght-vals1 $ght-vals2))) ($vector-andmap (lambda (k v) (equal? (hashtable-ref $ght k #f) v)) $ght-keys1 $ght-vals1) ($vector-andmap (lambda (k v) (equal? (hashtable-ref $ght k #f) v)) $ght-keys2 $ght-vals2) ($vector-andmap (lambda (k v) (equal? (hashtable-ref $ght k #f) v)) '#((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))) $ght-vals2) ($vector-andmap (lambda (k) (hashtable-contains? $ght k)) $ght-keys1) ($vector-andmap (lambda (k) (hashtable-contains? $ght k)) $ght-keys2) (not (hashtable-contains? $ght '(not a key))) (eq? (hashtable-ref $ght '(not a key) 'not-a-key) 'not-a-key) (begin (define $ght2 (hashtable-copy $ght)) (and (hashtable? $ght2) (not (hashtable-mutable? $ght2)) (not (hashtable-weak? $ght2)))) (eq? (hashtable-hash-function $ght) equal-hash) (eq? (hashtable-equivalence-function $ght) equal?) (begin (define $ght3 (hashtable-copy $ght #t)) (and (hashtable? $ght3) (hashtable-mutable? $ght3) (not (hashtable-weak? $ght3)))) (eq? (hashtable-hash-function $ght) equal-hash) (eq? (hashtable-equivalence-function $ght) equal?) (begin (vector-for-each (lambda (k) (hashtable-delete! $ght k)) $ght-keys1) #t) (same-elements? (hashtable-keys $ght) $ght-keys2) (same-elements? (hashtable-values $ght) $ght-vals2) (equal-entries? (hashtable-entries $ght) $ght-keys2 $ght-vals2) (eqv? (hashtable-size $ght) (vector-length $ght-keys2)) (begin (vector-for-each (lambda (k) (hashtable-delete! $ght k)) $ght-keys2) #t) (same-elements? (hashtable-keys $ght) '#()) (same-elements? (hashtable-values $ght) '#()) (equal-entries? (hashtable-entries $ght) '#() '#()) (eqv? (hashtable-size $ght) 0) (eqv? (#%$hashtable-veclen $ght) 8) ; make sure copies are unaffected by deletions (eq? (hashtable-size $ght2) (+ (vector-length $ght-keys1) (vector-length $ght-keys2))) (same-elements? (hashtable-keys $ght2) ($vector-append $ght-keys1 $ght-keys2)) (same-elements? (hashtable-values $ght2) ($vector-append $ght-vals1 $ght-vals2)) (equal-entries? (hashtable-entries $ght2) ($vector-append $ght-keys1 $ght-keys2) ($vector-append $ght-vals1 $ght-vals2)) (eq? (hashtable-size $ght3) (+ (vector-length $ght-keys1) (vector-length $ght-keys2))) (same-elements? (hashtable-keys $ght3) ($vector-append $ght-keys1 $ght-keys2)) (same-elements? (hashtable-values $ght3) ($vector-append $ght-vals1 $ght-vals2)) (equal-entries? (hashtable-entries $ght3) ($vector-append $ght-keys1 $ght-keys2) ($vector-append $ght-vals1 $ght-vals2)) (begin (hashtable-clear! $ght3) (and (eqv? (hashtable-size $ght3) 0) (eqv? (hashtable-size $ght2) (+ (vector-length $ght-keys1) (vector-length $ght-keys2))))) (error? ; not mutable (hashtable-clear! $ght2)) (error? ; not mutable (hashtable-delete! $ght2 (vector-ref $ght-keys2 0))) (error? ; not mutable (hashtable-update! $ght2 (vector-ref $ght-keys2 0) (lambda (x) (cons x x)) 'oops)) (error? ; not mutable (hashtable-update! $ght2 '(not a key) (lambda (x) (cons x x)) 'oops)) (eqv? (hashtable-update! $ght3 '(a . b) (lambda (x) (+ x 15)) 17) (void)) (eqv? (hashtable-update! $ght3 '(a . b) (lambda (x) (+ x 29)) 17) (void)) (eqv? (hashtable-update! $ght3 1e23 (lambda (x) (- x 5)) 19) (void)) (equal? (let ([a (hashtable-cell $ght3 '(a . b) 17)]) (set-cdr! a (+ (cdr a) 100)) a) '((a . b) . 161)) (equal? (let ([a (hashtable-cell $ght3 #vu8(1 2 3) 'bv)]) (set-cdr! a (cons (cdr a) 'vb)) a) '(#vu8(1 2 3) . (bv . vb))) (same-elements? (hashtable-keys $ght3) '#((a . b) 1e23 #vu8(1 2 3))) (same-elements? (hashtable-values $ght3) '#(161 14 (bv . vb))) (equal-entries? (hashtable-entries $ght3) '#((a . b) 1e23 #vu8(1 2 3)) '#(161 14 (bv . vb))) (let () ; carl's test program, with a few additions (define cov:prof-hash (lambda (V) (* (vector-ref V 0) (vector-ref V 1) (vector-ref V 2)))) (define cov:prof-equal? (lambda (V W) (let ((rv (and (= (vector-ref V 0) (vector-ref W 0)) (= (vector-ref V 1) (vector-ref W 1)) (= (vector-ref V 2) (vector-ref W 2))))) rv))) (define make-random-vector-key (lambda () (vector (random 20000) (random 100) (random 1000)))) (define test-hash (lambda (n) (let ([ht (make-hashtable cov:prof-hash cov:prof-equal?)]) (let loop ([i 0]) (let ([str (make-random-vector-key)]) (hashtable-set! ht str i) (hashtable-update! ht str (lambda (x) (* x 2)) -1) (let ([a (hashtable-cell ht str 'a)]) (set-cdr! a (- (cdr a)))) (cond [(= i n) (= (hashtable-size ht) 1000)] [(and (hashtable-contains? ht str) (= (hashtable-ref ht str #f) (* i -2))) (when (= (hashtable-size ht) 1000) (hashtable-delete! ht str)) (loop (+ i 1))] [else (errorf 'test-hash "hashtable failure for key ~s" str)])))))) (test-hash 100000)) ) (mat hash-functions ; equal-hash (error? ; wrong argument count (equal-hash)) (error? ; wrong argument count (equal-hash 0 0)) ; symbol-hash (error? ; wrong argument count (symbol-hash)) (error? ; wrong argument count (symbol-hash 'a 'a)) (error? ; not a symbol (symbol-hash "hello")) ; string-hash (error? ; wrong argument count (string-hash)) (error? ; wrong argument count (string-hash 'a 'a)) (error? ; not a string (string-hash 'hello)) ; string-ci-hash (error? ; wrong argument count (string-ci-hash)) (error? ; wrong argument count (string-ci-hash 'a 'a)) (error? ; not a string (string-ci-hash 'hello)) (let ([hc (equal-hash '(a b c))]) (and (integer? hc) (exact? hc) (>= hc 0) (= (equal-hash '(a b c)) hc))) (let ([hc (string-hash "hello")]) (and (integer? hc) (exact? hc) (>= hc 0) (= (string-hash "hello") hc))) (let ([hc (string-ci-hash "hello")]) (and (integer? hc) (exact? hc) (>= hc 0) (= (string-ci-hash "HelLo") hc))) (let f ([ls (oblist)]) (define okay? (lambda (x) (let ([hc (symbol-hash x)]) (and (integer? hc) (exact? hc) (>= hc 0) (= (symbol-hash x) hc))))) (and (okay? (car ls)) (let g ([ls ls] [n 10]) (or (null? ls) (if (= n 0) (f ls) (g (cdr ls) (- n 1))))))) ; adapted from Flatt's r6rs tests for string-ci=? (eqv? (string-ci-hash "z") (string-ci-hash "Z")) (not (eqv? (string-ci-hash "z") (string-ci-hash "a"))) (eqv? (string-ci-hash "Stra\xDF;e") (string-ci-hash "Strasse")) (eqv? (string-ci-hash "Stra\xDF;e") (string-ci-hash "STRASSE")) (eqv? (string-ci-hash "\x39E;\x391;\x39F;\x3A3;") (string-ci-hash "\x3BE;\x3B1;\x3BF;\x3C2;")) (eqv? (string-ci-hash "\x39E;\x391;\x39F;\x3A3;") (string-ci-hash "\x3BE;\x3B1;\x3BF;\x3C3;")) ) (mat fasl-eq-hashtable ; fasling out eq hash tables (equal? (let ([x (cons 'y '!)]) (define ht (make-eq-hashtable)) (eq-hashtable-set! ht x 'because) (eq-hashtable-set! ht 'foo "foo") (let ([p (open-file-output-port "testfile.ss" (file-options replace))]) (fasl-write (list x ht) p) (close-port p)) (let-values ([(x2 ht2) (apply values (call-with-port (open-file-input-port "testfile.ss") fasl-read))]) (list (eq-hashtable-ref ht2 x2 #f) (eq-hashtable-ref ht2 'foo #f)))) '(because "foo")) ; fasling out weak eq hash table (equal? (with-interrupts-disabled (let ([x (cons 'y '!)]) (define ht (make-weak-eq-hashtable)) (eq-hashtable-set! ht x 'because) (eq-hashtable-set! ht 'foo "foo") (let ([p (open-file-output-port "testfile.ss" (file-options replace))]) (fasl-write (list x ht) p) (close-port p)) (let-values ([(x2 ht2) (apply values (call-with-port (open-file-input-port "testfile.ss") fasl-read))]) (list (eq-hashtable-ref ht2 x2 #f) (eq-hashtable-ref ht2 'foo #f))))) '(because "foo")) (equal? (let ([ht2 (cadr (call-with-port (open-file-input-port "testfile.ss") fasl-read))]) (collect (collect-maximum-generation)) (list (hashtable-keys ht2) (eq-hashtable-ref ht2 'foo #f))) '(#(foo) "foo")) ; fasling eq hash tables via compile-file (begin (with-output-to-file "testfile.ss" (lambda () (pretty-print '(begin (define-syntax $feh-ls (let ([ls '(1 2 3)]) (lambda (x) #`(quote #,(datum->syntax #'* ls))))) (define $feh-ht (let () (define-syntax a (let ([ht (make-eq-hashtable)]) (eq-hashtable-set! ht 'q 'p) (eq-hashtable-set! ht $feh-ls (cdr $feh-ls)) (eq-hashtable-set! ht (cdr $feh-ls) (cddr $feh-ls)) (eq-hashtable-set! ht (cddr $feh-ls) $feh-ls) (lambda (x) #`(quote #,(datum->syntax #'* ht))))) a))))) 'replace) (compile-file "testfile") (load "testfile.so") #t) (eq? (eq-hashtable-ref $feh-ht 'q #f) 'p) (eq? (eq-hashtable-ref $feh-ht $feh-ls #f) (cdr $feh-ls)) (eq? (eq-hashtable-ref $feh-ht (cdr $feh-ls) #f) (cddr $feh-ls)) (eq? (eq-hashtable-ref $feh-ht (cddr $feh-ls) #f) $feh-ls) (begin (eq-hashtable-set! $feh-ht 'p 'r) #t) (eq? (eq-hashtable-ref $feh-ht 'p #f) 'r) (begin (eq-hashtable-set! $feh-ht 'q 'not-p) #t) (eq? (eq-hashtable-ref $feh-ht 'q #f) 'not-p) ) (mat fasl-symbol-hashtable ; fasling out symbol hash tables (equal? (let () (define ht (make-hashtable symbol-hash eq?)) (symbol-hashtable-set! ht 'why? 'because) (symbol-hashtable-set! ht 'foo "foo") (let ([p (open-file-output-port "testfile.ss" (file-options replace))]) (fasl-write ht p) (close-port p)) (let ([ht2 (call-with-port (open-file-input-port "testfile.ss") fasl-read)]) (list (symbol-hashtable-ref ht2 'why? #f) (symbol-hashtable-ref ht2 'foo #f)))) '(because "foo")) (#%$fasl-file-equal? "testfile.ss" "testfile.ss") (eqv? (strip-fasl-file "testfile.ss" "testfile1.ss" (fasl-strip-options)) (void)) (#%$fasl-file-equal? "testfile.ss" "testfile1.ss") (equal? (let ([ht2 (call-with-port (open-file-input-port "testfile1.ss" (file-options compressed)) fasl-read)]) (list (symbol-hashtable-ref ht2 'why? #f) (symbol-hashtable-ref ht2 'foo #f))) '(because "foo")) (begin (call-with-port (open-file-output-port "testfile1.ss" (file-options replace)) (lambda (p) (fasl-write (call-with-port (open-file-input-port "testfile.ss") fasl-read) p))) #t) (#%$fasl-file-equal? "testfile.ss" "testfile1.ss") (#%$fasl-file-equal? "testfile1.ss" "testfile.ss") (begin (call-with-port (open-file-output-port "testfile1.ss" (file-options replace)) (lambda (p) (let ([ht (call-with-port (open-file-input-port "testfile.ss") fasl-read)]) (symbol-hashtable-set! ht 'why? 'why-not?) (fasl-write ht p)))) #t) (not (#%$fasl-file-equal? "testfile.ss" "testfile1.ss")) (not (#%$fasl-file-equal? "testfile1.ss" "testfile.ss")) (begin (call-with-port (open-file-output-port "testfile1.ss" (file-options replace)) (lambda (p) (let ([ht (call-with-port (open-file-input-port "testfile.ss") fasl-read)]) (symbol-hashtable-set! ht (gensym) 'foiled) (fasl-write ht p)))) #t) (not (#%$fasl-file-equal? "testfile.ss" "testfile1.ss")) (not (#%$fasl-file-equal? "testfile1.ss" "testfile.ss")) ; fasling symbol hash tables via compile-file (begin (with-output-to-file "testfile.ss" (lambda () (pretty-print '(define $fsh-ht (let () (define-syntax a (let ([ht (make-hashtable symbol-hash symbol=?)]) (symbol-hashtable-set! ht 'q 'p) (symbol-hashtable-set! ht 'p 's) (let ([g (gensym "hello")]) (symbol-hashtable-set! ht g g) (symbol-hashtable-set! ht 'g g)) (lambda (x) #`(quote #,(datum->syntax #'* ht))))) a)))) 'replace) (compile-file "testfile") (load "testfile.so") #t) (eq? (symbol-hashtable-ref $fsh-ht 'q #f) 'p) (eq? (symbol-hashtable-ref $fsh-ht 'p #f) 's) (let ([g (symbol-hashtable-ref $fsh-ht 'g #f)]) (eq? (symbol-hashtable-ref $fsh-ht g #f) g)) (eq? (symbol-hashtable-ref $fsh-ht 'spam #f) #f) (begin (symbol-hashtable-set! $fsh-ht 'p 'r) #t) (eq? (symbol-hashtable-ref $fsh-ht 'p #f) 'r) (begin (symbol-hashtable-set! $fsh-ht 'q 'not-p) #t) (eq? (symbol-hashtable-ref $fsh-ht 'q #f) 'not-p) ) (mat fasl-other-hashtable ; can't fasl out other kinds of hashtables (error? (let ([x (cons 'y '!)]) (define ht (make-eqv-hashtable)) (hashtable-set! ht x 'because) (hashtable-set! ht 'foo "foo") (hashtable-set! ht 3.1415 "pi") (let ([p (open-file-output-port "testfile.ss" (file-options replace))]) (with-exception-handler (lambda (c) (close-port p) (raise-continuable c)) (lambda () (fasl-write (list x ht) p)))))) (error? (let ([x (cons 'y '!)]) (define ht (make-hashtable string-hash string=?)) (hashtable-set! ht "hello" 'goodbye) (let ([p (open-file-output-port "testfile.ss" (file-options replace))]) (with-exception-handler (lambda (c) (close-port p) (raise-continuable c)) (lambda () (fasl-write (list x ht) p)))))) ) (mat ht (begin (display-string (separate-eval '(parameterize ([source-directories '("." "../s" "../../s")]) (load "ht.ss")))) #t) )