Implementation of new, very efficient EQ?-hash tables. These tables
authorChris Hanson <org/chris-hanson/cph>
Fri, 8 Oct 1993 11:03:27 +0000 (11:03 +0000)
committerChris Hanson <org/chris-hanson/cph>
Fri, 8 Oct 1993 11:03:27 +0000 (11:03 +0000)
use address hashing, automatically rehash themselves when garbage
collections move their keys around, and automatically clean themselves
as their keys are reclaimed by the GC.  MAKE-EQ-HASH-TABLE is used to
create these tables; MAKE-OBJECT-HASH-TABLE and MAKE-SYMBOL-HASH-TABLE
are now aliases for this new procedure.

HASH-TABLE/SIZE now returns the "usable size" of the table, as claimed
by the documentation, rather than the "physical size".

New enumeration procedures HASH-TABLE->ALIST, HASH-TABLE/KEY-LIST, and
HASH-TABLE/DATUM-LIST.

v7/src/runtime/hashtb.scm
v7/src/runtime/runtime.pkg
v8/src/runtime/runtime.pkg

index 39e99c496ebd96c7d94417a51c1fda0f51b86d68..c58067f38f7c56906fd016e6ecd1df70e23374f6 100644 (file)
@@ -1,6 +1,6 @@
 #| -*-Scheme-*-
 
-$Id: hashtb.scm,v 1.4 1993/10/07 06:03:53 cph Exp $
+$Id: hashtb.scm,v 1.5 1993/10/08 11:03:16 cph Exp $
 
 Copyright (c) 1990-93 Massachusetts Institute of Technology
 
@@ -80,7 +80,8 @@ MIT in each case. |#
   grow-size
   shrink-size
   buckets
-  primes)
+  primes
+  (needs-rehash? #f))
 
 (define (hash-table/constructor key-hash key=? make-entry entry-valid?
                                entry-key entry-datum set-entry-datum!)
@@ -101,7 +102,7 @@ MIT in each case. |#
                              entry-key
                              entry-datum
                              set-entry-datum!
-                             initial-size
+                             (max initial-size minimum-size)
                              default-rehash-threshold
                              default-rehash-size)))
        (clear-table! table)
@@ -128,12 +129,11 @@ MIT in each case. |#
   (define-export set-entry-datum!)
   (define-export rehash-threshold)
   (define-export rehash-size)
-  (define-export count)
-  (define-export size))
+  (define-export count))
 
-;; Define old names for compatibility:
-(define hash-table/entry-value hash-table/entry-datum)
-(define hash-table/set-entry-value! hash-table/set-entry-datum!)
+(define (hash-table/size table)
+  (guarantee-hash-table table 'HASH-TABLE/SIZE)
+  (table-grow-size table))
 
 (define (set-hash-table/rehash-threshold! table threshold)
   (guarantee-hash-table table 'SET-HASH-TABLE/REHASH-THRESHOLD!)
@@ -192,9 +192,7 @@ MIT in each case. |#
 (define (hash-table/get table key default)
   (guarantee-hash-table table 'HASH-TABLE/GET)
   (let ((entries
-        (let ((buckets (table-buckets table)))
-          (vector-ref buckets
-                      ((table-key-hash table) key (vector-length buckets))))))
+        (vector-ref (table-buckets table) (compute-key-hash table key))))
     (if (and key (table-standard-accessors? table))
        ;; Optimize standard case: compiler makes this fast.
        (let loop ((entries entries))
@@ -205,60 +203,59 @@ MIT in each case. |#
                (else
                 (loop (cdr entries)))))
        (let ((key=? (table-key=? table))
-             (entry-key (table-entry-key table))
-             (entry-datum (table-entry-datum table)))
+             (entry-key (table-entry-key table)))
          (let loop ((entries entries))
            (cond ((null? entries)
                   default)
                  ((key=? (entry-key (car entries)) key)
-                  (entry-datum (car entries)))
+                  ((table-entry-datum table) (car entries)))
                  (else
                   (loop (cdr entries)))))))))
 
 (define hash-table/lookup
   (let ((default (list #f)))
     (lambda (table key if-found if-not-found)
-      (let ((value (hash-table/get table key default)))
-       (if (eq? value default)
+      (let ((datum (hash-table/get table key default)))
+       (if (eq? datum default)
            (if-not-found)
-           (if-found value))))))
+           (if-found datum))))))
 \f
 ;;;; Modifiers
 
-(define (hash-table/put! table key value)
+(define (hash-table/put! table key datum)
   (guarantee-hash-table table 'HASH-TABLE/PUT!)
-  (let ((buckets (table-buckets table)))
-    (let ((hash ((table-key-hash table) key (vector-length buckets))))
-      (let ((add-bucket!
-            (lambda ()
-              (without-interrupts
-               (lambda ()
-                 (let ((count (fix:+ (table-count table) 1)))
-                   (set-table-count! table count)
-                   (vector-set! buckets
-                                hash
-                                (cons ((table-make-entry table) key value)
-                                      (vector-ref buckets hash)))
-                   (if (> count (table-grow-size table))
-                       (grow-table! table))))))))
-       (if (and key (table-standard-accessors? table))
+  (let ((buckets (table-buckets table))
+       (hash (compute-key-hash table key)))
+    (let ((add-bucket!
+          (lambda ()
+            (without-interrupts
+             (lambda ()
+               (vector-set! buckets
+                            hash
+                            (cons ((table-make-entry table) key datum)
+                                  (vector-ref buckets hash)))
+               (if (> (let ((count (fix:+ (table-count table) 1)))
+                        (set-table-count! table count)
+                        count)
+                      (table-grow-size table))
+                   (grow-table! table)))))))
+      (if (and key (table-standard-accessors? table))
+         (let loop ((entries (vector-ref buckets hash)))
+           (cond ((null? entries)
+                  (add-bucket!))
+                 ((eq? (system-pair-car (car entries)) key)
+                  (system-pair-set-cdr! (car entries) datum))
+                 (else
+                  (loop (cdr entries)))))
+         (let ((key=? (table-key=? table))
+               (entry-key (table-entry-key table)))
            (let loop ((entries (vector-ref buckets hash)))
              (cond ((null? entries)
                     (add-bucket!))
-                   ((eq? (system-pair-car (car entries)) key)
-                    (system-pair-set-cdr! (car entries) value))
+                   ((key=? (entry-key (car entries)) key)
+                    ((table-set-entry-datum! table) (car entries) datum))
                    (else
-                    (loop (cdr entries)))))
-           (let ((key=? (table-key=? table))
-                 (entry-key (table-entry-key table))
-                 (set-entry-datum! (table-set-entry-datum! table)))
-             (let loop ((entries (vector-ref buckets hash)))
-               (cond ((null? entries)
-                      (add-bucket!))
-                     ((key=? (entry-key (car entries)) key)
-                      (set-entry-datum! (car entries) value))
-                     (else
-                      (loop (cdr entries)))))))))))
+                    (loop (cdr entries))))))))))
 
 (define (hash-table/remove! table key)
   (guarantee-hash-table table 'HASH-TABLE/REMOVE!)
@@ -266,29 +263,30 @@ MIT in each case. |#
        (entry-key (table-entry-key table))
        (decrement-count
         (lambda ()
-          (let ((count (fix:- (table-count table) 1)))
-            (set-table-count! table count)
-            (if (< count (table-shrink-size table))
-                (shrink-table! table))))))
-    (let ((buckets (table-buckets table)))
-      (let ((hash ((table-key-hash table) key (vector-length buckets))))
-       (let ((entries (vector-ref buckets hash)))
-         (if (not (null? entries))
-             (let ((next (cdr entries)))
-               (if (key=? (entry-key (car entries)) key)
-                   (without-interrupts
-                    (lambda ()
-                      (vector-set! buckets hash next)
-                      (decrement-count)))
-                   (let loop ((previous entries) (entries next))
-                     (if (not (null? entries))
-                         (let ((next (cdr entries)))
-                           (if (key=? (entry-key (car entries)) key)
-                               (without-interrupts
-                                (lambda ()
-                                  (set-cdr! previous next)
-                                  (decrement-count)))
-                               (loop entries next)))))))))))))
+          (if (< (let ((count (fix:- (table-count table) 1)))
+                   (set-table-count! table count)
+                   count)
+                 (table-shrink-size table))
+              (shrink-table! table)))))
+    (let ((buckets (table-buckets table))
+         (hash (compute-key-hash table key)))
+      (let ((entries (vector-ref buckets hash)))
+       (if (not (null? entries))
+           (let ((next (cdr entries)))
+             (if (key=? (entry-key (car entries)) key)
+                 (without-interrupts
+                  (lambda ()
+                    (vector-set! buckets hash next)
+                    (decrement-count)))
+                 (let loop ((previous entries) (entries next))
+                   (if (not (null? entries))
+                       (let ((next (cdr entries)))
+                         (if (key=? (entry-key (car entries)) key)
+                             (without-interrupts
+                              (lambda ()
+                                (set-cdr! previous next)
+                                (decrement-count)))
+                             (loop entries next))))))))))))
 \f
 ;;;; Enumerators
 
@@ -303,15 +301,6 @@ MIT in each case. |#
                (procedure (entry-key entry) (entry-datum entry)))
              (hash-table/entries-list table))))
 
-(define (hash-table/entries-list table)
-  (guarantee-hash-table table 'HASH-TABLE/ENTRIES-LIST)
-  (let ((buckets (table-buckets table)))
-    (let ((n-buckets (vector-length buckets)))
-      (let loop ((n 0) (result '()))
-       (if (fix:< n n-buckets)
-           (loop (fix:+ n 1) (append (vector-ref buckets n) result))
-           result)))))
-
 (define (hash-table/entries-vector table)
   (guarantee-hash-table table 'HASH-TABLE/ENTRIES-VECTOR)
   (let ((result (make-vector (table-count table))))
@@ -326,6 +315,39 @@ MIT in each case. |#
                    (vector-set! result i (car entries))
                    (per-entry (cdr entries) (fix:+ i 1))))))))
     result))
+
+(define (hash-table/entries-list table)
+  (guarantee-hash-table table 'HASH-TABLE/ENTRIES-LIST)
+  (table->list table (lambda (entry) entry)))
+
+(define (hash-table->alist table)
+  (guarantee-hash-table table 'HASH-TABLE->ALIST)
+  (table->list table
+              (let ((entry-key (table-entry-key table))
+                    (entry-datum (table-entry-datum table)))
+                (lambda (entry)
+                  (cons (entry-key entry) (entry-datum entry))))))
+
+(define (hash-table/key-list table)
+  (guarantee-hash-table table 'HASH-TABLE/KEY-LIST)
+  (table->list table (table-entry-key table)))
+
+(define (hash-table/datum-list table)
+  (guarantee-hash-table table 'HASH-TABLE/DATUM-LIST)
+  (table->list table (table-entry-datum table)))
+
+(define (table->list table entry->element)
+  (let ((buckets (table-buckets table)))
+    (let ((n-buckets (vector-length buckets)))
+      (let loop ((n 0) (result '()))
+       (if (fix:< n n-buckets)
+           (loop (fix:+ n 1)
+                 (let loop ((entries (vector-ref buckets n)) (result result))
+                   (if (null? entries)
+                       result
+                       (loop (cdr entries)
+                             (cons (entry->element (car entries)) result)))))
+           result)))))
 \f
 ;;;; Cleansing
 
@@ -335,105 +357,115 @@ MIT in each case. |#
 
 (define (clear-table! table)
   (set-table-count! table 0)
-  (new-size! table (table-initial-size table) #f #f #f))
+  (reset-table! table (table-initial-size table) #f #f #f))
 
 (define (hash-table/clean! table)
   (guarantee-hash-table table 'HASH-TABLE/CLEAN!)
-  (let ((entry-valid? (table-entry-valid? table)))
-    ;; If `entry-valid?' is #t, then entries never become invalid.
-    (if (not (eq? entry-valid? #t))
-       (without-interrupts
-        (lambda ()
-          (let ((buckets (table-buckets table))
-                (count (table-count table)))
-            (let ((n-buckets (vector-length buckets)))
-              (do ((i 0 (fix:+ i 1)))
-                  ((fix:= i n-buckets))
-                (letrec
-                    ((scan-head
-                      (lambda (entries)
+  ;; If `entry-valid?' is #t, then entries never become invalid.
+  (if (not (eq? (table-entry-valid? table) #t))
+      (without-interrupts
+       (lambda ()
+        (clean-table! table)
+        (if (< (table-count table) (table-shrink-size table))
+            (shrink-table! table))))))
+
+(define (clean-table! table)
+  (let ((buckets (table-buckets table))
+       (entry-valid? (table-entry-valid? table)))
+    (let ((n-buckets (vector-length buckets)))
+      (do ((i 0 (fix:+ i 1)))
+         ((fix:= i n-buckets))
+       (letrec
+           ((scan-head
+             (lambda (entries)
+               (cond ((null? entries)
+                      (vector-set! buckets i entries))
+                     ((entry-valid? (car entries))
+                      (vector-set! buckets i entries)
+                      (scan-tail entries (cdr entries)))
+                     (else
+                      (set-table-count! table (fix:- (table-count table) 1))
+                      (scan-head (cdr entries))))))
+            (scan-tail
+             (lambda (previous entries)
+               (cond ((null? entries)
+                      unspecific)
+                     ((entry-valid? (car entries))
+                      (scan-tail entries (cdr entries)))
+                     (else
+                      (set-table-count! table (fix:- (table-count table) 1))
+                      (let loop ((entries (cdr entries)))
                         (cond ((null? entries)
-                               (vector-set! buckets i entries))
+                               (set-cdr! previous entries))
                               ((entry-valid? (car entries))
-                               (vector-set! buckets i entries)
+                               (set-cdr! previous entries)
                                (scan-tail entries (cdr entries)))
                               (else
-                               (set! count (fix:- count 1))
-                               (scan-head (cdr entries))))))
-                     (scan-tail
-                      (lambda (previous entries)
-                        (if (not (null? entries))
-                            (if (entry-valid? (car entries))
-                                (scan-tail entries (cdr entries))
-                                (begin
-                                  (set! count (fix:- count 1))
-                                  (let loop ((entries (cdr entries)))
-                                    (cond ((null? entries)
-                                           (set-cdr! previous entries))
-                                          ((entry-valid? (car entries))
-                                           (set-cdr! previous entries)
-                                           (scan-tail entries (cdr entries)))
-                                          (else
-                                           (set! count (fix:- count 1))
-                                           (loop (cdr entries)))))))))))
-                  (let ((entries (vector-ref buckets i)))
-                    (if (not (null? entries))
-                        (if (entry-valid? (car entries))
-                            (scan-tail entries (cdr entries))
-                            (begin
-                              (set! count (fix:- count 1))
-                              (scan-head (cdr entries)))))))))
-            (set-table-count! table count)
-            (if (< count (table-shrink-size table))
-                (shrink-table! table))))))))
+                               (set-table-count! table
+                                                 (fix:- (table-count table)
+                                                        1))
+                               (loop (cdr entries))))))))))
+         (let ((entries (vector-ref buckets i)))
+           (cond ((null? entries)
+                  unspecific)
+                 ((entry-valid? (car entries))
+                  (scan-tail entries (cdr entries)))
+                 (else
+                  (set-table-count! table (fix:- (table-count table) 1))
+                  (scan-head (cdr entries))))))))))
 \f
 ;;;; Resizing
 
 (define (grow-table! table)
-  (let ((old-buckets (table-buckets table)))
-    (let ((count (table-count table))
-         (rehash-size (table-rehash-size table)))
-      (let loop ((size (table-size table)))
-       (let ((grow-size (compute-grow-size table size)))
-         (if (> count grow-size)
-             (loop (if (exact-integer? rehash-size)
-                       (+ size rehash-size)
-                       (let ((size* (round->exact (* size rehash-size))))
-                         (if (> size* size)
-                             size*
-                             (+ size 1)))))
-             (new-size! table size grow-size #f (table-primes table))))))
-    (rehash-buckets! table old-buckets)))
-
-(define (compute-grow-size table size)
-  (round->exact (* (table-rehash-threshold table) size)))
+  (let ((count (table-count table))
+       (rehash-size (table-rehash-size table)))
+    (let loop ((size (table-size table)))
+      (let ((grow-size (compute-grow-size table size)))
+       (if (> count grow-size)
+           (loop (if (exact-integer? rehash-size)
+                     (+ size rehash-size)
+                     (let ((size* (round->exact (* size rehash-size))))
+                       (if (> size* size)
+                           size*
+                           (+ size 1)))))
+           (new-size! table size grow-size #f (table-primes table)))))))
 
 (define (shrink-table! table)
-  (let ((old-buckets (table-buckets table)))
-    (let ((count (table-count table))
-         (rehash-size (table-rehash-size table)))
-      (let loop ((size (table-size table)))
-       (let ((shrink-size (compute-shrink-size table size)))
-         (if (< count shrink-size)
-             (loop (if (exact-integer? rehash-size)
-                       (- size rehash-size)
-                       (let ((size* (round->exact (/ size rehash-size))))
-                         (if (< size* size)
-                             size*
-                             (- size 1)))))
-             (new-size! table size #f shrink-size #f)))))
-    (rehash-buckets! table old-buckets)))
-
-(define (compute-shrink-size table size)
-  (if (<= size minimum-size)
-      0
-      (round->exact (* (table-rehash-threshold table)
-                      (let ((rehash-size (table-rehash-size table)))
-                        (if (exact-integer? rehash-size)
-                            (- size (+ rehash-size rehash-size))
-                            (/ size (* rehash-size rehash-size))))))))
+  (let ((count (table-count table))
+       (rehash-size (table-rehash-size table)))
+    (let loop ((size (table-size table)))
+      (let ((shrink-size (compute-shrink-size table size)))
+       (if (< count shrink-size)
+           (loop (if (exact-integer? rehash-size)
+                     (- size rehash-size)
+                     (let ((size* (round->exact (/ size rehash-size))))
+                       (if (< size* size)
+                           size*
+                           (- size 1)))))
+           (new-size! table size #f shrink-size #f))))))
 
 (define (new-size! table size grow-size shrink-size primes)
+  (let ((old-buckets (table-buckets table)))
+    (reset-table! table size grow-size shrink-size primes)
+    (let ((buckets (table-buckets table))
+         (key-hash (table-key-hash table))
+         (entry-key (table-entry-key table)))
+      (let ((old-n-buckets (vector-length old-buckets))
+           (n-buckets (vector-length buckets)))
+       ;; Clear NEEDS-REHASH? before starting the rehash; if it's set
+       ;; during the rehash that will tell us that GC occurred.
+       (set-table-needs-rehash?! table #f)
+       (do ((i 0 (fix:+ i 1)))
+           ((fix:= i old-n-buckets))
+         (let loop ((entries (vector-ref old-buckets i)))
+           (if (not (null? entries))
+               (let ((next (cdr entries))
+                     (hash (key-hash (entry-key (car entries)) n-buckets)))
+                 (set-cdr! entries (vector-ref buckets hash))
+                 (vector-set! buckets hash entries)
+                 (loop next)))))))))
+
+(define (reset-table! table size grow-size shrink-size primes)
   (let ((size (max size minimum-size)))
     (set-table-size! table size)
     (set-table-grow-size! table (or grow-size (compute-grow-size table size)))
@@ -447,45 +479,165 @@ MIT in each case. |#
       (set-table-primes! table primes)
       (set-table-buckets! table (make-vector (stream-car primes) '())))))
 
-(define (rehash-buckets! table old-buckets)
-  (let ((buckets (table-buckets table))
-       (key-hash (table-key-hash table))
-       (entry-key (table-entry-key table)))
-    (let ((old-n-buckets (vector-length old-buckets))
-         (n-buckets (vector-length buckets)))
-      (do ((i 0 (fix:+ i 1)))
-         ((fix:= i old-n-buckets))
-       (let loop ((entries (vector-ref old-buckets i)))
-         (if (not (null? entries))
-             (let ((next (cdr entries))
-                   (hash (key-hash (entry-key (car entries)) n-buckets)))
-               (set-cdr! entries (vector-ref buckets hash))
-               (vector-set! buckets hash entries)
-               (loop next))))))))
+(define (compute-grow-size table size)
+  (round->exact (* (table-rehash-threshold table) size)))
+
+(define (compute-shrink-size table size)
+  (if (<= size minimum-size)
+      0
+      (round->exact (* (table-rehash-threshold table)
+                      (let ((rehash-size (table-rehash-size table)))
+                        (if (exact-integer? rehash-size)
+                            (- size (+ rehash-size rehash-size))
+                            (/ size (* rehash-size rehash-size))))))))
 \f
-;;;; Common Constructors
-
-(define (make-object-hash-table #!optional initial-size)
-  (let ((object-table (hash-table/make)))
-    ((hash-table/constructor (lambda (object modulus)
-                              (if object
-                                  (remainder (object-hash object
-                                                          object-table
-                                                          #t)
-                                             modulus)
-                                  0))
-                            eq?
-                            weak-cons
-                            weak-pair/car?
-                            weak-car
-                            weak-cdr
-                            weak-set-cdr!)
-     (if (default-object? initial-size) #f initial-size))))
+;;;; EQ?-Hash Tables
+
+;;; EQ?-hash tables compute their hash number from the address of the
+;;; key.  Because the address is changed by the garbage collector, it
+;;; is necessary to rehash the table after a garbage collection.
+
+;;; Rehashing the table during the garbage collection is undesirable
+;;; for these reasons:
+;;; 1. The time required to rehash the table is proportional to the
+;;;    number of items in the table, which can be quite large.  It's
+;;;    undesirable for the garbage collection time to be extended this
+;;;    way.
+;;; 2. If the garbage collector rearranges the internals of the table,
+;;;    then nearly every operation on the table must be locked to
+;;;    prevent garbage collection from occurring while it runs.  This
+;;;    means long periods with interrupts disabled, plus the overhead
+;;;    of interrupt locking that is otherwise unnecessary.
+;;; 3. If the table isn't used in between two garbage collections,
+;;;    then the effort to rehash it during the first garbage
+;;;    collection is wasted.
+
+;;; For these reasons, rehashing of the table is performed lazily.
+;;; When the garbage collector runs, it sets the table's NEEDS-REHASH?
+;;; flag.  This flag is examined by all of the hash-table operations
+;;; to see if it is necessary to rehash the table before performing
+;;; the operation.  Since the only reason for rehashing the table is
+;;; to ensure consistency between the table's contents and the result
+;;; of the address hashing operation, it is sufficient check this flag
+;;; whenever the address hashing is performed.  This means that the
+;;; rehashing of the table and the computing of the corresponding
+;;; address hash must occur atomically with respect to the garbage
+;;; collector.
+
+;;; The only tricky part about this algorithm is that the garbage
+;;; collector might run while the table is being resized.  If this
+;;; occurs, part of the table might be hashed correctly, while the
+;;; rest would be incorrect.  This is not a problem because resizing
+;;; (with one exception) is always the last thing done by an
+;;; operation.  If the garbage collection occurs during a resizing,
+;;; the NEEDS-REHASH? flag will be set after the resizing is
+;;; completed, and the next operation will rehash the table.
+
+;;; The exception to this rule is COMPUTE-KEY-HASH, which might have
+;;; to shrink the table due to keys which have been garbage collected.
+;;; COMPUTE-KEY-HASH explicitly checks for this possibility, and
+;;; rehashes the table again if necessary.
+
+(define (compute-key-hash table key)
+  (if (eq? eq-hash (table-key-hash table))
+      (let ((interrupt-mask (set-interrupt-enables! interrupt-mask/none)))
+       (let loop ()
+         (if (table-needs-rehash? table)
+             (begin
+               (rehash-eq-hash-table! table)
+               (if (< (table-count table) (table-shrink-size table))
+                   (begin
+                     (set-interrupt-enables! interrupt-mask/gc-ok)
+                     (shrink-table! table)
+                     (set-interrupt-enables! interrupt-mask/none)
+                     (loop))
+                   (set-table-needs-rehash?! table #f)))))
+       (let ((hash (eq-hash key (vector-length (table-buckets table)))))
+         (set-interrupt-enables! interrupt-mask)
+         hash))
+      ((table-key-hash table) key (vector-length (table-buckets table)))))
+\f
+(define (make-eq-hash-table #!optional initial-size)
+  (let ((table
+        (%make-eq-hash-table (and (not (default-object? initial-size))
+                                  initial-size))))
+    (set! eq-hash-tables (weak-cons table eq-hash-tables))
+    table))
+
+(define (rehash-eq-hash-table! table)
+  (let ((buckets (table-buckets table)))
+    (let ((n-buckets (vector-length buckets)))
+      (let loop
+         ((entries
+           (let ((entries '()))
+             (do ((i 0 (fix:+ i 1)))
+                 ((fix:= i n-buckets))
+               (let ((bucket (vector-ref buckets i)))
+                 (if (not (null? bucket))
+                     (begin
+                       (let loop ((bucket bucket))
+                         (if (null? (cdr bucket))
+                             (set-cdr! bucket entries)
+                             (loop (cdr bucket))))
+                       (set! entries bucket)
+                       (vector-set! buckets i '())))))
+             entries)))
+       (if (not (null? entries))
+           (let ((rest (cdr entries)))
+             (if (system-pair-car (car entries))
+                 (let ((hash
+                        (eq-hash (system-pair-car (car entries)) n-buckets)))
+                   (set-cdr! entries (vector-ref buckets hash))
+                   (vector-set! buckets hash entries))
+                 (set-table-count! table (fix:- (table-count table) 1)))
+             (loop rest)))))))
+
+(define-integrable (eq-hash key modulus)
+  (fix:remainder (let ((n
+                       ((ucode-primitive primitive-object-set-type)
+                        (ucode-type fixnum)
+                        key)))
+                  (if (fix:< n 0)
+                      (fix:not n)
+                      n))
+                modulus))
+
+(define (mark-eq-hash-tables!)
+  (let loop ((previous #f) (tables eq-hash-tables))
+    (cond ((null? tables)
+          unspecific)
+         ((system-pair-car tables)
+          (set-table-needs-rehash?! (system-pair-car tables) #t)
+          (loop tables (system-pair-cdr tables)))
+         (else
+          (if previous
+              (set-cdr! previous (system-pair-cdr tables))
+              (set! eq-hash-tables (system-pair-cdr tables)))
+          (loop previous (system-pair-cdr tables))))))
+\f
+;;;; Initialization
 
+;; Define old names for compatibility:
+(define hash-table/entry-value hash-table/entry-datum)
+(define hash-table/set-entry-value! hash-table/set-entry-datum!)
+(define make-object-hash-table make-eq-hash-table)
+(define make-symbol-hash-table make-eq-hash-table)
+
+(define %make-eq-hash-table)
+(define eq-hash-tables)
 (define make-string-hash-table)
-(define make-symbol-hash-table)
 
 (define (initialize-package!)
+  (set! %make-eq-hash-table
+       (hash-table/constructor eq-hash
+                               eq?
+                               weak-cons
+                               weak-pair/car?
+                               weak-car
+                               weak-cdr
+                               weak-set-cdr!))
+  (set! eq-hash-tables '())
+  (add-primitive-gc-daemon! mark-eq-hash-tables!)
   (set! make-string-hash-table
        (hash-table/constructor string-hash-mod
                                string=?
@@ -494,12 +646,4 @@ MIT in each case. |#
                                car
                                cdr
                                set-cdr!))
-  (set! make-symbol-hash-table
-       (hash-table/constructor symbol-hash-mod
-                               eq?
-                               cons
-                               #t
-                               car
-                               cdr
-                               set-cdr!))
   unspecific)
\ No newline at end of file
index 80f9ef28afd52c96f2c17e9022df61aecead57c0..a5cd49d178718fa41533d0540ed73390c9b92aa2 100644 (file)
@@ -1,6 +1,6 @@
 #| -*-Scheme-*-
 
-$Id: runtime.pkg,v 14.198 1993/10/07 04:30:40 cph Exp $
+$Id: runtime.pkg,v 14.199 1993/10/08 11:03:27 cph Exp $
 
 Copyright (c) 1988-1993 Massachusetts Institute of Technology
 
@@ -720,6 +720,8 @@ MIT in each case. |#
          trigger-secondary-gc-daemons!)
   (export (runtime hash)
          add-primitive-gc-daemon!)
+  (export (runtime hash-table)
+         add-primitive-gc-daemon!)
   (export (runtime interrupt-handler)
          trigger-gc-daemons!)
   (initialization (initialize-package!)))
@@ -859,10 +861,12 @@ MIT in each case. |#
     (else))
   (parent ())
   (export ()
+         hash-table->alist
          hash-table/clean!
          hash-table/clear!
          hash-table/constructor
          hash-table/count
+         hash-table/datum-list
          hash-table/entries-list
          hash-table/entries-vector
          hash-table/entry-datum
@@ -871,6 +875,7 @@ MIT in each case. |#
          hash-table/for-each
          hash-table/get
          hash-table/key-hash
+         hash-table/key-list
          hash-table/key=?
          hash-table/lookup
          hash-table/make-entry
@@ -882,6 +887,7 @@ MIT in each case. |#
          hash-table/set-entry-value!
          hash-table/size
          hash-table?
+         make-eq-hash-table
          make-object-hash-table
          make-string-hash-table
          make-symbol-hash-table
index 80f9ef28afd52c96f2c17e9022df61aecead57c0..a5cd49d178718fa41533d0540ed73390c9b92aa2 100644 (file)
@@ -1,6 +1,6 @@
 #| -*-Scheme-*-
 
-$Id: runtime.pkg,v 14.198 1993/10/07 04:30:40 cph Exp $
+$Id: runtime.pkg,v 14.199 1993/10/08 11:03:27 cph Exp $
 
 Copyright (c) 1988-1993 Massachusetts Institute of Technology
 
@@ -720,6 +720,8 @@ MIT in each case. |#
          trigger-secondary-gc-daemons!)
   (export (runtime hash)
          add-primitive-gc-daemon!)
+  (export (runtime hash-table)
+         add-primitive-gc-daemon!)
   (export (runtime interrupt-handler)
          trigger-gc-daemons!)
   (initialization (initialize-package!)))
@@ -859,10 +861,12 @@ MIT in each case. |#
     (else))
   (parent ())
   (export ()
+         hash-table->alist
          hash-table/clean!
          hash-table/clear!
          hash-table/constructor
          hash-table/count
+         hash-table/datum-list
          hash-table/entries-list
          hash-table/entries-vector
          hash-table/entry-datum
@@ -871,6 +875,7 @@ MIT in each case. |#
          hash-table/for-each
          hash-table/get
          hash-table/key-hash
+         hash-table/key-list
          hash-table/key=?
          hash-table/lookup
          hash-table/make-entry
@@ -882,6 +887,7 @@ MIT in each case. |#
          hash-table/set-entry-value!
          hash-table/size
          hash-table?
+         make-eq-hash-table
          make-object-hash-table
          make-string-hash-table
          make-symbol-hash-table