racket/collects/rnrs/hashtables-6.rkt
2010-04-27 16:50:15 -06:00

163 lines
5.9 KiB
Racket

#lang scheme/base
(require scheme/dict)
(provide make-eq-hashtable
make-eqv-hashtable
(rename-out [r6rs:make-hashtable make-hashtable])
hashtable?
hashtable-size
hashtable-ref
hashtable-set!
hashtable-delete!
hashtable-contains?
hashtable-update!
hashtable-copy
hashtable-clear!
hashtable-keys
hashtable-entries
hashtable-equivalence-function
hashtable-hash-function
hashtable-mutable?
equal-hash
string-hash
string-ci-hash
symbol-hash)
(define-struct hashtable ([ht #:mutable]
wrap
unwrap
mutable?
equivalence-function
hash-function)
#:property prop:dict
(vector (case-lambda
[(ht key)
(hash-ref (hashtable-ht ht) ((hashtable-wrap ht) key))]
[(ht key default)
(hash-ref (hashtable-ht ht) ((hashtable-wrap ht) key) default)])
(lambda (ht key val) (hashtable-set! ht key val))
#f
(lambda (ht key) (hashtable-delete! ht key))
#f
(lambda (ht) (hashtable-size ht))
(lambda (ht) (hash-iterate-first (hashtable-ht ht)))
(lambda (ht pos) (hash-iterate-next (hashtable-ht ht) pos))
(lambda (ht pos) ((hashtable-unwrap ht)
(hash-iterate-key (hashtable-ht ht) pos)))
(lambda (ht pos) (hash-iterate-value (hashtable-ht ht) pos))))
(define-struct eqv-box (val)
#:property prop:equal+hash (list
(lambda (a b recur) (eqv? (eqv-box-val a)
(eqv-box-val b)))
(lambda (v recur) (equal-hash-code (eqv-box-val v)))
(lambda (v recur) (equal-secondary-hash-code (eqv-box-val v)))))
(define (make-eq-hashtable [k 0])
(unless (exact-nonnegative-integer? k)
(raise-type-error 'make-eq-hashtable "exact, nonnegative integer" k))
(make-hashtable (make-hasheq) values values #t eq? #f))
(define (make-eqv-hashtable [k 0])
(unless (exact-nonnegative-integer? k)
(raise-type-error 'make-eqv-hashtable "exact, nonnegative integer" k))
(make-hashtable (make-hash) make-eqv-box eqv-box-val #t eqv? #f))
(define r6rs:make-hashtable
(let ([make-hashtable
(lambda (hash =? [k 0])
(unless (and (procedure? hash)
(procedure-arity-includes? hash 1))
(raise-type-error 'make-hashtable "procedure (arity 1)" hash))
(unless (and (procedure? =?)
(procedure-arity-includes? =? 2))
(raise-type-error 'make-hashtable "procedure (arity 2)" =?))
(unless (exact-nonnegative-integer? k)
(raise-type-error 'make-hashtable "exact, nonnegative integer" k))
(let ()
(define-struct hash-box (val)
#:property prop:equal+hash (list
(lambda (a b recur) (=? (hash-box-val a)
(hash-box-val b)))
(lambda (v recur) (hash (hash-box-val v)))
(lambda (v recur) 10001)))
(make-hashtable (make-hash) make-hash-box hash-box-val #t =? hash)))])
make-hashtable))
(define (hashtable-size ht)
(hash-count (hashtable-ht ht)))
(define tag (gensym))
(define (hashtable-ref ht key default)
(let ([v (hash-ref (hashtable-ht ht) ((hashtable-wrap ht) key) tag)])
(if (eq? v tag)
default
v)))
(define (hashtable-set! ht key val)
(if (hashtable-mutable? ht)
(hash-set! (hashtable-ht ht) ((hashtable-wrap ht) key) val)
(raise-type-error 'hashtable-set! "mutable hashtable" ht)))
(define (hashtable-delete! ht key)
(if (hashtable-mutable? ht)
(hash-remove! (hashtable-ht ht) ((hashtable-wrap ht) key))
(raise-type-error 'hashtable-delete! "mutable hashtable" ht)))
(define (hashtable-contains? ht key)
(not (eq? (hash-ref (hashtable-ht ht) ((hashtable-wrap ht) key) tag)
tag)))
(define (hashtable-update! ht key proc default)
(if (hashtable-mutable? ht)
(hashtable-set! ht key (proc (hashtable-ref ht key default)))
(raise-type-error 'hashtable-update! "mutable hashtable" ht)))
(define (hashtable-copy ht [mutable? #f])
(make-hashtable (hash-copy (hashtable-ht ht))
(hashtable-wrap ht)
(hashtable-unwrap ht)
mutable?
(hashtable-equivalence-function ht)
(hashtable-hash-function ht)))
(define (hashtable-clear! ht [k 0])
(unless (exact-nonnegative-integer? k)
(raise-type-error 'hashtable-clear! "exact, nonnegative integer" k))
(if (hashtable-mutable? ht)
(set-hashtable-ht! ht (if (eq? values (hashtable-wrap ht))
(make-hasheq)
(make-hash)))
(raise-type-error 'hashtable-clear! "mutable hashtable" ht)))
(define (hashtable-keys ht)
(let ([unwrap (hashtable-unwrap ht)])
(list->vector (hash-map (hashtable-ht ht) (lambda (a b) (unwrap a))))))
(define (hashtable-entries ht)
(let ([ps (hash-map (hashtable-ht ht) cons)]
[unwrap (hashtable-unwrap ht)])
(values (list->vector (map (lambda (p) (unwrap (car p))) ps))
(list->vector (map cdr ps)))))
(define (equal-hash v)
(abs (equal-hash-code v)))
(define (string-hash s)
(unless (string? s)
(raise-type-error 'string-hash "string" s))
(abs (equal-hash-code s)))
(define (string-ci-hash s)
(unless (string? s)
(raise-type-error 'string-ci-hash "string" s))
(abs (equal-hash-code (string-foldcase s))))
(define (symbol-hash s)
(unless (symbol? s)
(raise-type-error 'symbol-hash "symbol" s))
(abs (eq-hash-code s)))