/
basic-hash-tables.sls
153 lines (127 loc) · 4.73 KB
/
basic-hash-tables.sls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!r6rs
;; Copyright (C) 2009 Andreas Rottmann. All rights reserved. Licensed
;; under an MIT-style license. See the file LICENSE in the original
;; collection this file is distributed with.
(library (surfage s69 basic-hash-tables)
(export
;; Type constructors and predicate
make-hash-table hash-table? alist->hash-table
;; Reflective queries
hash-table-equivalence-function hash-table-hash-function
;; Dealing with single elements
hash-table-ref hash-table-ref/default hash-table-set!
hash-table-delete! hash-table-exists?
hash-table-update! hash-table-update!/default
;; Dealing with the whole contents
hash-table-size hash-table-keys hash-table-values hash-table-walk
hash-table-fold hash-table->alist hash-table-copy hash-table-merge!
;; Hashing
hash string-hash string-ci-hash hash-by-identity)
(import
(rename (rnrs)
(string-hash rnrs:string-hash)
(string-ci-hash rnrs:string-ci-hash)))
(define make-hash-table
(case-lambda
((eql? hash)
(make-hashtable hash eql?))
((eql?)
(cond ((eq? eql? eq?)
(make-eq-hashtable))
((eq? eql? eqv?)
(make-eqv-hashtable))
((eq? eql? equal?)
(make-hashtable equal-hash eql?))
((eq? eql? string=?)
(make-hashtable rnrs:string-hash eql?))
((eq? eql? string-ci=?)
(make-hashtable rnrs:string-ci-hash eql?))
(else
(assertion-violation 'make-hash-table
"unrecognized equivalence predicate" eql?))))
(()
(make-hashtable equal-hash equal?))))
(define hash-table? hashtable?)
(define not-there (list 'not-there))
(define (alist->hash-table alist . args)
(let ((table (apply make-hash-table args)))
(for-each (lambda (entry)
(hashtable-update! table
(car entry)
(lambda (x)
(if (eq? x not-there) (cdr entry) x))
not-there))
alist)
table))
(define hash-table-equivalence-function hashtable-equivalence-function)
(define hash-table-hash-function hashtable-hash-function)
(define (failure-thunk who key)
(lambda ()
(assertion-violation who "no association for key" key)))
(define hash-table-ref
(case-lambda
((table key thunk)
(let ((val (hashtable-ref table key not-there)))
(if (eq? val not-there)
(thunk)
val)))
((table key)
(hash-table-ref table key (failure-thunk 'hash-table-ref key)))))
(define hash-table-ref/default hashtable-ref)
(define hash-table-set! hashtable-set!)
(define hash-table-delete! hashtable-delete!)
(define hash-table-exists? hashtable-contains?)
(define hash-table-update!
(case-lambda
((table key proc thunk)
(hashtable-update! table
key
(lambda (val)
(if (eq? val not-there)
(thunk)
(proc val)))
not-there))
((table key proc)
(hash-table-update! table key proc (failure-thunk 'hash-table-update! key)))))
(define hash-table-update!/default hashtable-update!)
(define hash-table-size hashtable-size)
(define (hash-table-keys table)
(vector->list (hashtable-keys table)))
(define (hash-table-values table)
(let-values (((keys values) (hashtable-entries table)))
(vector->list values)))
(define (hash-table-walk table proc)
(let-values (((keys values) (hashtable-entries table)))
(vector-for-each proc keys values)))
(define (hash-table-fold table kons knil)
(let-values (((keys values) (hashtable-entries table)))
(let ((size (vector-length keys)))
(let loop ((i 0)
(val knil))
(if (>= i size)
val
(loop (+ i 1)
(kons (vector-ref keys i) (vector-ref values i) val)))))))
(define (hash-table->alist table)
(hash-table-fold table
(lambda (k v l)
(cons (cons k v) l))
'()))
(define hash-table-copy hashtable-copy)
(define (hash-table-merge! table1 table2)
(hash-table-walk table2 (lambda (k v)
(hashtable-set! table1 k v)))
table1)
(define (make-hasher hash-proc)
(case-lambda
((obj)
;; R6RS doesn't guarantee that the result of the hash procedure
;; is non-negative, so we use mod.
(mod (hash-proc obj) (greatest-fixnum)))
((obj bound)
(mod (hash-proc obj) bound))))
(define hash (make-hasher equal-hash))
(define hash-by-identity (make-hasher equal-hash)) ;; Very slow.
(define string-hash (make-hasher rnrs:string-hash))
(define string-ci-hash (make-hasher rnrs:string-ci-hash))
)