aboutsummaryrefslogtreecommitdiffstats
path: root/hash-map.csc
diff options
context:
space:
mode:
Diffstat (limited to 'hash-map.csc')
-rw-r--r--hash-map.csc251
1 files changed, 251 insertions, 0 deletions
diff --git a/hash-map.csc b/hash-map.csc
new file mode 100644
index 0000000..2c95b36
--- /dev/null
+++ b/hash-map.csc
@@ -0,0 +1,251 @@
+(define-library (csc hash-map)
+ (export
+ alist->hash-map
+ hash-bytevector
+ hash-map->alist
+ hash-map-foreach
+ hash-map-insert
+ hash-map-lookup
+ hash-map?
+ make-hash-map)
+ (import (scheme base)
+ (only (csc format) sprintf))
+ (begin
+
+
+ (define-record-type <key-hash>
+ (make-key-hash hash k)
+ key-hash?
+ (hash key-hash-hash)
+ (k key-hash-value))
+
+
+ (define (key-hash<? k1 k2 key<?)
+ (cond ((< (key-hash-hash k1) (key-hash-hash k2)) #t)
+ ((> (key-hash-hash k1) (key-hash-hash k2)) #f)
+ ((key<? (key-hash-value k1) (key-hash-value k2)) #t)
+ (else #f)))
+
+
+ (define (key-hash=? k1 k2)
+ (and (= (key-hash-hash k1) (key-hash-hash k2)) (eqv? (key-hash-value k1) (key-hash-value k2))))
+
+
+ (define-record-type <node>
+ (make-node color key-hash val left right)
+ node?
+ (color node-color)
+ (key-hash node-key)
+ (val node-value)
+ (left node-left)
+ (right node-right))
+
+
+ (define (red? n)
+ (if (null? n)
+ #f
+ (eq? 'red (node-color n))))
+
+
+ (define (black? n)
+ (if (null? n)
+ #t
+ (eq? 'black (node-color n))))
+
+
+ (define (rebalance-left m)
+ (let ((p (node-left m))
+ (u (node-right m)))
+ (cond ((or
+ (and
+ (red? p)
+ (red? (node-left p))
+ (red? u))
+ (and
+ (red? p)
+ (red? (node-right p))
+ (red? u)))
+ ; b r
+ ; / \ / \
+ ; r r => b b
+ ; / /
+ ; r r
+
+ ; b r
+ ; / \ / \
+ ; r r => b b
+ ; \ \
+ ; r r
+ (make-node 'red (node-key m) (node-value m)
+ (make-node 'black (node-key p) (node-value p) (node-left p) (node-right p))
+ (make-node 'black (node-key u) (node-value u) (node-left u) (node-right u))))
+ ((and
+ (red? p)
+ (red? (node-right p))
+ (black? u))
+ ; b b
+ ; / \ / \
+ ; r b => r r
+ ; \ \
+ ; r b
+ (let ((n (node-right p)))
+ (make-node 'black (node-key n) (node-value n)
+ (make-node 'red (node-key p) (node-value p) (node-left p) (node-left n))
+ (make-node 'red (node-key m) (node-value m) (node-right n) u))))
+ ((and
+ (red? p)
+ (red? (node-left p))
+ (black? u))
+ ; b b
+ ; / \ / \
+ ; r b => r r
+ ; / \
+ ; r b
+ (make-node 'black (node-key p) (node-value p)
+ (node-left p)
+ (make-node 'red (node-key m) (node-value m) (node-right p) u)))
+ (else m))))
+
+
+ (define (rebalance-right m)
+ (let ((u (node-left m))
+ (p (node-right m)))
+ (cond ((or
+ (and
+ (red? u)
+ (red? p)
+ (red? (node-left p)))
+ (and
+ (red? u)
+ (red? p)
+ (red? (node-right p))))
+ ; b r
+ ; / \ / \
+ ; r r => b b
+ ; \ \
+ ; r r
+
+ ; b r
+ ; / \ / \
+ ; r r => b b
+ ; / /
+ ; r r
+ (make-node 'red (node-key m) (node-value m)
+ (make-node 'black (node-key u) (node-value u) (node-left u) (node-right u))
+ (make-node 'black (node-key p) (node-value p) (node-left p) (node-right p))))
+ ((and
+ (black? u)
+ (red? p)
+ (red? (node-left p)))
+ ; b b
+ ; / \ / \
+ ; b r => r r
+ ; / /
+ ; r b
+ (let ((n (node-left p)))
+ (make-node 'black (node-key n) (node-value n)
+ (make-node 'red (node-key m) (node-value m) u (node-left n))
+ (make-node 'red (node-key p) (node-value p) (node-right n) (node-right p)))))
+ ((and
+ (black? u)
+ (red? p)
+ (red? (node-right p)))
+ ; b b
+ ; / \ / \
+ ; b r => r r
+ ; \ /
+ ; r b
+ (make-node 'black (node-key p) (node-value p)
+ (make-node 'red (node-key m) (node-value m) u (node-left p))
+ (node-right p)))
+ (else m))))
+
+
+ (define (insert m k v key<?)
+ (cond ((null? m) (make-node 'red k v '() '()))
+ ((key-hash<? k (node-key m) key<?)
+ (rebalance-left
+ (make-node (node-color m) (node-key m) (node-value m)
+ (insert (node-left m) k v key<?)
+ (node-right m))))
+ ((key-hash=? k (node-key m)) (make-node (node-color m) k v (node-left m) (node-right m)))
+ (else
+ (rebalance-right
+ (make-node (node-color m) (node-key m) (node-value m)
+ (node-left m)
+ (insert (node-right m) k v key<?))))))
+
+
+ (define-record-type <hash-map>
+ (construct-hash-map hash key<? root)
+ hash-map?
+ (hash hash-map-hash)
+ (key<? hash-map-key<?)
+ (root hash-map-root))
+
+
+ (define (make-hash-map hash key<?)
+ (construct-hash-map hash key<? '()))
+
+
+ (define (hash-map-insert m k v)
+ (let* ((shuffle
+ (lambda (hash)
+ (truncate-remainder
+ (* #x9e3779b97f4a7c55 hash)
+ #x10000000000000000)))
+ (res (insert (hash-map-root m) (make-key-hash (shuffle ((hash-map-hash m) k)) k) v (hash-map-key<? m))))
+ (construct-hash-map
+ (hash-map-hash m)
+ (hash-map-key<? m)
+ (make-node 'black (node-key res) (node-value res) (node-left res) (node-right res)))))
+
+
+ (define-record-type <key-not-found-error>
+ (make-key-not-found-error)
+ key-not-found-error?)
+
+
+ (define (hash-map-lookup m k)
+ (letrec ((lookup
+ (lambda (n)
+ (cond ((null? n) (raise (make-key-not-found-error)))
+ ((key-hash<? k (node-key n) (hash-map-key<? m)) (lookup (node-left n)))
+ ((key-hash=? k (node-key n)) (node-value n))
+ (else (lookup (node-right n)))))))
+ (lookup (hash-map-root m))))
+
+
+ (define (hash-map-foreach f m)
+ (letrec ((node-foreach
+ (lambda (n)
+ (unless (null? n)
+ (node-foreach (node-left n))
+ (f (key-hash-value (node-key n)) (node-value n))
+ (node-foreach (node-right n))))))
+ (node-foreach (hash-map-root m))))
+
+
+ (define (hash-map->alist m)
+ (let ((alist '()))
+ (hash-map-foreach
+ (lambda (k v)
+ (set! alist (cons (cons k v) alist)))
+ m)
+ alist))
+
+
+ (define (alist->hash-map hash key<? alist)
+ (let loop ((alist alist)
+ (m (make-hash-map hash key<?)))
+ (if (null? alist)
+ m
+ (loop (cdr alist) (hash-map-insert m (caar alist) (cdar alist))))))
+
+
+ (define (hash-bytevector b)
+ (let loop ((i 0)
+ (hash 0))
+ (if (>= i (bytevector-length b))
+ hash
+ (loop (+ 1 i) (+ (* hash #x100) (bytevector-u8-ref b i))))))))