(module weak-map mzscheme
(require (lib "contract.ss"))
(define-struct weak-map (ht))
(provide struct:weak-map weak-map? weak-map)
(provide/contract [rename -make-weak-map make-weak-map
(case->
(-> weak-map?)
((one-of/c 'equal) . -> . weak-map?))])
(define -make-weak-map
(case-lambda
[()
(make-weak-map (make-hash-table 'weak))]
[(flag)
(make-weak-map (make-hash-table flag 'weak))]))
(provide/contract [weak-map-put! (weak-map? any/c any/c . -> . any)])
(define (weak-map-put! m k v)
(hash-table-put! (weak-map-ht m) k (make-ephemeron k (box v))))
(provide/contract [weak-map-get (case->
(weak-map? any/c . -> . any)
(weak-map? any/c any/c . -> . any))])
(define weak-map-get
(case-lambda
[(m k)
(weak-map-get
m k (lambda () (error 'weak-map-get "no value found for key ~a" k)))]
[(m k thunk-or-value)
(let ([v (hash-table-get (weak-map-ht m) k (lambda () #f))])
(if v
(let ([v (ephemeron-value v)])
(if v
(unbox v)
(if (procedure? thunk-or-value)
(thunk-or-value)
thunk-or-value)))
(if (procedure? thunk-or-value)
(thunk-or-value)
thunk-or-value)))]))
(provide/contract [weak-map-for-each (weak-map? (any/c any/c . -> . any) . -> . any)])
(define (weak-map-for-each m f)
(hash-table-for-each
(weak-map-ht m)
(lambda (k weak-v)
(let ([v (ephemeron-value weak-v)])
(when v
(f k (unbox v)))))))
(provide/contract [weak-map-map (weak-map? (any/c any/c . -> . any) . -> . (listof any/c))])
(define (weak-map-map m f)
(define results '())
(weak-map-for-each
m
(lambda (k v)
(set! results (cons (f k v) results))))
(reverse! results)))