\f
;;;; Table operations
-(define ((hash-table-constructor type) #!optional initial-size)
- (%make-hash-table type initial-size))
+(define (hash-table-constructor type)
+ (guarantee hash-table-type? type 'hash-table-constructor)
+ (lambda (#!optional initial-size)
+ (%make-hash-table type initial-size 'hash-table-constructor)))
-(define (%make-hash-table type #!optional initial-size)
- (guarantee hash-table-type? type '%make-hash-table)
+(define (make-hash-table* type #!optional initial-size)
+ (guarantee hash-table-type? type 'make-hash-table*)
+ (%make-hash-table type initial-size 'make-hash-table*))
+
+(define (%make-hash-table type initial-size caller)
(let ((initial-size
(if (or (default-object? initial-size) (not initial-size))
#f
(begin
- (guarantee exact-nonnegative-integer? initial-size
- '%make-hash-table)
+ (guarantee exact-nonnegative-integer? initial-size caller)
initial-size))))
(let ((table (make-table type)))
(if (and initial-size (> initial-size minimum-size))
\f
;;;; Entries of various flavours
+(define all-entry-types '())
+
+(define (register-entry-type! name type)
+ (set! all-entry-types
+ (cons (cons name type)
+ all-entry-types))
+ unspecific)
+
+(define (entry-type-name? name)
+ (and (assq name all-entry-types) #t))
+
+(define (get-entry-type name)
+ (cdr (assq name all-entry-types)))
+
+(define (hash-table-entry-type-names)
+ (map car all-entry-types))
+
;;; Strong
(define-integrable make-strong-entry cons)
call-with-strong-entry-key
call-with-strong-entry-key&datum
set-strong-entry-datum!))
-
+(register-entry-type! 'strong hash-table-entry-type:strong)
+\f
;;; Key-weak -- if the key is GC'd, the entry is dropped, but the datum
;;; may be retained arbitrarily long.
call-with-key-weak-entry-key
call-with-key-weak-entry-key&datum
set-key-weak-entry-datum!))
+(register-entry-type! 'key-weak hash-table-entry-type:key-weak)
\f
;;; Datum-weak -- if the datum is GC'd, the entry is dropped, but the
;;; key may be retained arbitrarily long.
call-with-datum-weak-entry-key
call-with-datum-weak-entry-key&datum
set-datum-weak-entry-datum!))
+(register-entry-type! 'datum-weak hash-table-entry-type:datum-weak)
;;; Key-or-datum-weak -- if either is GC'd, the entry is dropped.
call-with-key/datum-weak-entry-key
call-with-key/datum-weak-entry-key&datum
set-key/datum-weak-entry-datum!))
+(register-entry-type! 'key/datum-weak hash-table-entry-type:key/datum-weak)
\f
;;; Key-ephemeral -- if the key is GC'd, the entry is dropped.
call-with-key-ephemeral-entry-key
call-with-key-ephemeral-entry-key&datum
set-key-ephemeral-entry-datum!))
+(register-entry-type! 'key-ephemeral hash-table-entry-type:key-ephemeral)
;;; Datum-ephemeral -- if the datum is GC'd, the entry is dropped
call-with-datum-ephemeral-entry-key
call-with-datum-ephemeral-entry-key&datum
set-datum-ephemeral-entry-datum!))
+(register-entry-type! 'datum-ephemeral hash-table-entry-type:datum-ephemeral)
\f
;;; Key-and-datum-ephemeral -- the entry is dropped iff both key and
;;; datum are GC'd.
call-with-key&datum-ephemeral-entry-key
call-with-key&datum-ephemeral-entry-key&datum
set-key&datum-ephemeral-entry-datum!))
+(register-entry-type! 'key&datum-ephemeral
+ hash-table-entry-type:key&datum-ephemeral)
\f
;;;; Methods
\f
;;;; Constructing and Open-Coding Types and Constructors
-(define (make-hash-table* key-hash key=? rehash-after-gc? entry-type
- #!optional initial-size)
- ((hash-table-constructor
- (make-hash-table-type key-hash key=? rehash-after-gc? entry-type))
- initial-size))
+(define (make-hash-table-type* key=? . options)
+ (receive (key-hash rehash-after-gc? entry-type-name)
+ (hash-table-type-options options 'make-hash-table-type*)
+ (make-hash-table-type (if (default-object? key-hash)
+ (equality-predicate-hasher key=?)
+ key-hash)
+ key=?
+ (if (default-object? rehash-after-gc?)
+ (equality-predicate-rehash-after-gc? key=?)
+ rehash-after-gc?)
+ (get-entry-type entry-type-name))))
+
+(define-deferred hash-table-type-options
+ (keyword-option-parser
+ (list (list 'hash-function unary-procedure? default-object)
+ (list 'rehash-after-gc? boolean? default-object)
+ (list 'entry-type entry-type-name? (lambda () 'strong)))))
(define (make-hash-table-type key-hash key=? rehash-after-gc? entry-type)
- (hash-table-intern! (follow-memo-crap key-hash key=? rehash-after-gc?)
+ (hash-table-intern! (hash-metadata key=? key-hash rehash-after-gc?)
entry-type
(lambda ()
(let ((constructor
(%make-hash-table-type key-hash key=? rehash-after-gc?
entry-type))))))
+(define (hash-metadata key-hash key=? rehash-after-gc?)
+ (let ((lookup
+ (lambda (get set)
+ (let ((pair
+ (hash-table-intern!
+ (hash-table-intern! hash-metadata-table
+ key-hash
+ make-key-ephemeral-eq-hash-table)
+ key=?
+ (lambda () (cons #f #f)))))
+ (or (get pair)
+ (let ((v (make-key-ephemeral-eq-hash-table)))
+ (set pair v)
+ v))))))
+ (if rehash-after-gc?
+ (lookup car set-car!)
+ (lookup cdr set-cdr!))))
+
(define (memoize-hash-table-type! key-hash key=? rehash-after-gc? entry-type
type)
- (let ((crap (follow-memo-crap key-hash key=? rehash-after-gc?)))
+ (let ((crap (hash-metadata key-hash key=? rehash-after-gc?)))
(cond ((hash-table-ref/default crap entry-type #f)
=> (lambda (type*)
(warn "Replacing memoized hash table type:" type type*))))
(hash-table-set! crap entry-type type)))
-
-(define (follow-memo-crap key-hash key=? rehash-after-gc?)
- (define (intern-car! pair generator)
- (or (car pair) (let ((v (generator))) (set-car! pair v) v)))
- (define (intern-cdr! pair generator)
- (or (cdr pair) (let ((v (generator))) (set-cdr! pair v) v)))
- ((if rehash-after-gc? intern-car! intern-cdr!)
- (hash-table-intern!
- (hash-table-intern! memoized-hash-table-types
- key-hash
- make-key-ephemeral-eq-hash-table)
- key=?
- (lambda () (cons #f #f)))
- make-key-ephemeral-eq-hash-table))
\f
(define (%make-hash-table-type key-hash key=? rehash-after-gc? entry-type)
(let ((compute-hash!
(define strong-eqv-hash-table-type)
(define hash-table-type-constructors)
-(define memoized-hash-table-types)
+(define hash-metadata-table)
(add-boot-init!
(lambda ()
(set! make-key-ephemeral-eq-hash-table
(hash-table-constructor key-ephemeral-eq-hash-table-type))
(set! hash-table-type-constructors (make-key-ephemeral-eq-hash-table))
- (set! memoized-hash-table-types (make-key-ephemeral-eq-hash-table))
+ (set! hash-metadata-table (make-key-ephemeral-eq-hash-table))
(memoize-hash-table-type! eq-hash-mod eq? #t
hash-table-entry-type:key-ephemeral
key-ephemeral-eq-hash-table-type)
hash-table-entry-type:key-weak))
(define (make-hash-table #!optional key=? key-hash . args)
- (declare (ignore args))
- (%make-hash-table
- (custom-table-type (if (default-object? key=?) equal? key=?)
- key-hash)
- (default-object)))
-
-(define (custom-table-type key=? key-hash)
- (make-hash-table-type (if (default-object? key-hash)
- (equality-predicate-hasher key=?)
- key-hash)
- key=?
- (if (or (eq? key=? string=?)
- (eq? key=? string-ci=?))
- #f ;No rehash needed after GC
- #t) ;Rehash needed after GC
- hash-table-entry-type:strong))
+ (make-hash-table*
+ (apply make-hash-table-type*
+ (if (default-object? key=?) equal? key=?)
+ (if (default-object? key-hash)
+ args
+ (cons* 'hash-function key-hash args)))))
(define (alist->hash-table alist #!optional key=? key-hash . args)
(guarantee alist? alist 'alist->hash-table)
(%set-equality-predicate-properties! equality-predicate
(cons* 'hasher hasher
'rehash-after-gc? rehash-after-gc?
- keylist)))
+ keylist)))
\ No newline at end of file