home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
mitsch75.zip
/
scheme-7_5_17-src.zip
/
scheme-7.5.17
/
src
/
runtime
/
geneqht.scm
< prev
next >
Wrap
Text File
|
1999-01-02
|
8KB
|
245 lines
#| -*-Scheme-*-
$Id: geneqht.scm,v 1.2 1999/01/02 06:11:34 cph Exp $
Copyright (c) 1990-1999 Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|#
;;;; EQ?-Hash Tables for Generic Procedures
(declare (usual-integrations))
(define (make-eqht)
(let ((table (%make-eqht)))
(reset-table! table)
(record-address-hash-table! table)
table))
(define (eqht/get table key default)
(let ((entries
(vector-ref (table-buckets table) (compute-key-hash table key))))
(let loop ((entries entries))
(cond ((null? entries)
default)
((eq? (system-pair-car (car entries)) key)
(system-pair-cdr (car entries)))
(else
(loop (cdr entries)))))))
(define (eqht/put! table key datum)
(let ((buckets (table-buckets table))
(hash (compute-key-hash table key)))
(let loop ((entries (vector-ref buckets hash)))
(cond ((null? entries)
(without-interrupts
(lambda ()
(vector-set! buckets
hash
(cons (weak-cons 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)))))
((eq? (system-pair-car (car entries)) key)
(system-pair-set-cdr! (car entries) datum))
(else
(loop (cdr entries)))))))
(define (eqht/for-each table procedure)
(for-each-vector-element (table-buckets table)
(lambda (entries)
(for-each (lambda (entry)
(if (system-pair-car entry)
(procedure (system-pair-car entry)
(system-pair-cdr entry))))
entries))))
;;;; Address Hashing
(define (compute-key-hash table key)
(let loop ()
(let ((hash (eq-hash-mod key (vector-length (table-buckets table)))))
(if (not (table-needs-rehash? table))
hash
(begin
(without-interrupts (lambda () (rehash-table! table)))
(loop))))))
(define-integrable (eq-hash-mod key modulus)
(fix:remainder (let ((n
((ucode-primitive primitive-object-set-type)
(ucode-type positive-fixnum)
key)))
(if (fix:< n 0)
(fix:not n)
n))
modulus))
(define (record-address-hash-table! table)
(set! address-hash-tables (weak-cons table address-hash-tables))
unspecific)
(define (mark-address-hash-tables!)
(let loop ((previous #f) (tables address-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
(system-pair-set-cdr! previous (system-pair-cdr tables))
(set! address-hash-tables (system-pair-cdr tables)))
(loop previous (system-pair-cdr tables))))))
(define address-hash-tables)
(define (initialize-address-hashing!)
(set! address-hash-tables '())
(add-primitive-gc-daemon! mark-address-hash-tables!))
;;;; Resizing
(define (grow-table! table)
(let loop ((size (table-grow-size table)))
(if (> (table-count table) size)
(loop (let ((size* (round->exact (* size 2.))))
(if (> size* size)
size*
(+ size 1))))
(new-size! table size))))
(define (shrink-table! table)
(let loop ((size (table-grow-size table)))
(cond ((<= size minimum-size)
(new-size! table minimum-size))
((< (table-count table) (compute-shrink-size size))
(loop (decrement-size size)))
(else
(new-size! table size)))))
(define (new-size! table size)
(set-table-grow-size! table size)
(let ((old-buckets (table-buckets table)))
(reset-table! table)
(rehash-table-from-old-buckets! table old-buckets)))
(define (reset-table! table)
(set-table-shrink-size! table (compute-shrink-size (table-grow-size table)))
(let ((primes
(let ((size (round->exact (table-grow-size table))))
(let loop
((primes
(if (< size (stream-car (table-primes table)))
prime-numbers-stream
(table-primes table))))
(if (<= size (stream-car primes))
primes
(loop (stream-cdr primes)))))))
(set-table-primes! table primes)
(set-table-buckets! table (make-vector (stream-car primes) '()))))
(define (compute-shrink-size size)
(if (<= size minimum-size)
0
(max 0 (decrement-size (decrement-size size)))))
(define (decrement-size size)
(let ((size* (round->exact (/ size 2.))))
(if (< size* size)
size*
(- size 1))))
;;;; Rehashing
(define (rehash-table-from-old-buckets! table buckets)
(let ((n-buckets (vector-length buckets)))
(set-table-needs-rehash?! table #f)
(do ((i 0 (fix:+ i 1)))
((fix:= i n-buckets))
(let ((entries (vector-ref buckets i)))
(if (not (null? entries))
(rehash-table-entries! table entries)))))
(maybe-shrink-table! table))
(define (rehash-table-entries! table entries)
(let ((buckets (table-buckets table)))
(let ((n-buckets (vector-length buckets)))
(let loop ((entries entries))
(if (not (null? entries))
(let ((rest (cdr entries)))
(if (system-pair-car (car entries))
(let ((hash
(eq-hash-mod (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 (maybe-shrink-table! table)
;; Since the rehashing also deletes invalid entries, the count
;; might have been reduced. So check to see if it's necessary to
;; shrink the table even further.
(if (< (table-count table) (table-shrink-size table))
(shrink-table! table)))
(define (rehash-table! table)
(let ((entries (extract-table-entries! table)))
(set-table-needs-rehash?! table #f)
(rehash-table-entries! table entries))
(maybe-shrink-table! table))
(define (extract-table-entries! table)
(let ((buckets (table-buckets table)))
(let ((n-buckets (vector-length buckets)))
(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))))
;;;; Miscellaneous
(define-structure (eqht (constructor %make-eqht ()) (conc-name table-))
(count 0)
(grow-size minimum-size)
(shrink-size 0)
buckets
(primes prime-numbers-stream)
(needs-rehash? #f))
(define-integrable minimum-size 4)
(define-integrable (without-interrupts thunk)
(let ((interrupt-mask (set-interrupt-enables! interrupt-mask/gc-ok)))
(thunk)
(set-interrupt-enables! interrupt-mask)
unspecific))
(define-integrable (weak-cons car cdr)
(system-pair-cons (ucode-type weak-cons) car cdr))