mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-23 13:00:34 +02:00
Add "transient" intmap interface
* module/language/cps/intmap.scm (make-atomic-reference): (get-atomic-reference, set-atomic-reference!): New helpers. (*branch-size-with-edit*, *edit-index*): Branches now have a trailing field, an atomic reference to their owner. (<transient-intmap>): New record type. A mutable intmap. (new-branch): Set the "edit" field on the branch. (clone-branch-and-set): No editor for this field. (assert-readable!, writable-branch): New helpers. (transient-intmap, persistent-intmap): New exported functions. (intmap-add!): New function. (intmap-next, intmap-prev, intmap-ref): Work on transient intmaps. (intmap-fold): Persist the intmap before folding over it.
This commit is contained in:
parent
cf512e3268
commit
95db570528
1 changed files with 171 additions and 31 deletions
|
@ -32,10 +32,15 @@
|
||||||
|
|
||||||
(define-module (language cps intmap)
|
(define-module (language cps intmap)
|
||||||
#:use-module (srfi srfi-9)
|
#:use-module (srfi srfi-9)
|
||||||
|
#:use-module (srfi srfi-18)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
#:export (empty-intmap
|
#:export (empty-intmap
|
||||||
intmap?
|
intmap?
|
||||||
|
transient-intmap?
|
||||||
|
persistent-intmap
|
||||||
|
transient-intmap
|
||||||
intmap-add
|
intmap-add
|
||||||
|
intmap-add!
|
||||||
intmap-remove
|
intmap-remove
|
||||||
intmap-ref
|
intmap-ref
|
||||||
intmap-next
|
intmap-next
|
||||||
|
@ -49,8 +54,18 @@
|
||||||
(define-syntax-rule (define-inline name val)
|
(define-syntax-rule (define-inline name val)
|
||||||
(define-syntax name (identifier-syntax val)))
|
(define-syntax name (identifier-syntax val)))
|
||||||
|
|
||||||
|
;; FIXME: This should make an actual atomic reference.
|
||||||
|
(define-inlinable (make-atomic-reference value)
|
||||||
|
(list value))
|
||||||
|
(define-inlinable (get-atomic-reference reference)
|
||||||
|
(car reference))
|
||||||
|
(define-inlinable (set-atomic-reference! reference value)
|
||||||
|
(set-car! reference value))
|
||||||
|
|
||||||
(define-inline *branch-bits* 5)
|
(define-inline *branch-bits* 5)
|
||||||
(define-inline *branch-size* (ash 1 *branch-bits*))
|
(define-inline *branch-size* (ash 1 *branch-bits*))
|
||||||
|
(define-inline *branch-size-with-edit* (1+ *branch-size*))
|
||||||
|
(define-inline *edit-index* *branch-size*)
|
||||||
(define-inline *branch-mask* (1- *branch-size*))
|
(define-inline *branch-mask* (1- *branch-size*))
|
||||||
|
|
||||||
(define-record-type <intmap>
|
(define-record-type <intmap>
|
||||||
|
@ -60,20 +75,38 @@
|
||||||
(shift intmap-shift)
|
(shift intmap-shift)
|
||||||
(root intmap-root))
|
(root intmap-root))
|
||||||
|
|
||||||
(define (new-branch)
|
(define-record-type <transient-intmap>
|
||||||
(make-vector *branch-size* #f))
|
(make-transient-intmap min shift root edit)
|
||||||
|
transient-intmap?
|
||||||
|
(min transient-intmap-min set-transient-intmap-min!)
|
||||||
|
(shift transient-intmap-shift set-transient-intmap-shift!)
|
||||||
|
(root transient-intmap-root set-transient-intmap-root!)
|
||||||
|
(edit transient-intmap-edit set-transient-intmap-edit!))
|
||||||
|
|
||||||
|
(define-inlinable (new-branch edit)
|
||||||
|
(let ((vec (make-vector *branch-size-with-edit* #f)))
|
||||||
|
(when edit (vector-set! vec *edit-index* edit))
|
||||||
|
vec))
|
||||||
(define (clone-branch-and-set branch i elt)
|
(define (clone-branch-and-set branch i elt)
|
||||||
(let ((new (new-branch)))
|
(let ((new (new-branch #f)))
|
||||||
(when branch (vector-move-left! branch 0 *branch-size* new 0))
|
(when branch (vector-move-left! branch 0 *branch-size* new 0))
|
||||||
(vector-set! new i elt)
|
(vector-set! new i elt)
|
||||||
new))
|
new))
|
||||||
|
(define-inlinable (assert-readable! root-edit)
|
||||||
|
(unless (eq? (get-atomic-reference root-edit) (current-thread))
|
||||||
|
(error "Transient intmap owned by another thread" root-edit)))
|
||||||
|
(define-inlinable (writable-branch branch root-edit)
|
||||||
|
(let ((edit (vector-ref branch *edit-index*)))
|
||||||
|
(if (eq? root-edit edit)
|
||||||
|
branch
|
||||||
|
(clone-branch-and-set branch *edit-index* root-edit))))
|
||||||
(define (branch-empty? branch)
|
(define (branch-empty? branch)
|
||||||
(let lp ((i 0))
|
(let lp ((i 0))
|
||||||
(or (= i *branch-size*)
|
(or (= i *branch-size*)
|
||||||
(and (not (vector-ref branch i))
|
(and (not (vector-ref branch i))
|
||||||
(lp (1+ i))))))
|
(lp (1+ i))))))
|
||||||
|
|
||||||
(define (round-down min shift)
|
(define-inlinable (round-down min shift)
|
||||||
(logand min (lognot (1- (ash 1 shift)))))
|
(logand min (lognot (1- (ash 1 shift)))))
|
||||||
|
|
||||||
(define empty-intmap (make-intmap 0 0 #f))
|
(define empty-intmap (make-intmap 0 0 #f))
|
||||||
|
@ -107,6 +140,92 @@
|
||||||
(define (meet-error old new)
|
(define (meet-error old new)
|
||||||
(error "Multiple differing values and no meet procedure defined" old new))
|
(error "Multiple differing values and no meet procedure defined" old new))
|
||||||
|
|
||||||
|
(define* (transient-intmap #:optional (source empty-intmap))
|
||||||
|
(match source
|
||||||
|
(($ <transient-intmap> min shift root edit)
|
||||||
|
(assert-readable! edit)
|
||||||
|
source)
|
||||||
|
(($ <intmap> min shift root)
|
||||||
|
(let ((edit (make-atomic-reference (current-thread))))
|
||||||
|
(make-transient-intmap min shift root edit)))))
|
||||||
|
|
||||||
|
(define* (persistent-intmap #:optional (source empty-intmap))
|
||||||
|
(match source
|
||||||
|
(($ <transient-intmap> min shift root edit)
|
||||||
|
(assert-readable! edit)
|
||||||
|
;; Make a fresh reference, causing any further operations on this
|
||||||
|
;; transient to clone its root afresh.
|
||||||
|
(set-transient-intmap-edit! source
|
||||||
|
(make-atomic-reference (current-thread)))
|
||||||
|
;; Clear the reference to the current thread, causing our edited
|
||||||
|
;; data structures to be persistent again.
|
||||||
|
(set-atomic-reference! edit #f)
|
||||||
|
(if min
|
||||||
|
(make-intmap min shift root)
|
||||||
|
empty-intmap))
|
||||||
|
(($ <intmap>)
|
||||||
|
source)))
|
||||||
|
|
||||||
|
(define* (intmap-add! map i val #:optional (meet meet-error))
|
||||||
|
(define (ensure-branch! root idx)
|
||||||
|
(let ((edit (vector-ref root *edit-index*)))
|
||||||
|
(match (vector-ref root idx)
|
||||||
|
(#f (let ((v (new-branch edit)))
|
||||||
|
(vector-set! root idx v)
|
||||||
|
v))
|
||||||
|
(v (writable-branch v edit)))))
|
||||||
|
(define (adjoin! i shift root)
|
||||||
|
(let* ((shift (- shift *branch-bits*))
|
||||||
|
(idx (logand (ash i (- shift)) *branch-mask*)))
|
||||||
|
(cond
|
||||||
|
((zero? shift)
|
||||||
|
(let ((node (vector-ref root idx)))
|
||||||
|
(unless (eq? node val)
|
||||||
|
(vector-set! root idx (if node (meet node val) val)))))
|
||||||
|
(else
|
||||||
|
(adjoin! i shift (ensure-branch! root idx))))))
|
||||||
|
(match map
|
||||||
|
(($ <transient-intmap> min shift root edit)
|
||||||
|
(assert-readable! edit)
|
||||||
|
(cond
|
||||||
|
((< i 0)
|
||||||
|
;; The power-of-two spanning trick doesn't work across 0.
|
||||||
|
(error "Intmaps can only map non-negative integers." i))
|
||||||
|
((not root)
|
||||||
|
(set-transient-intmap-min! map i)
|
||||||
|
(set-transient-intmap-shift! map 0)
|
||||||
|
(set-transient-intmap-root! map val))
|
||||||
|
((and (<= min i) (< i (+ min (ash 1 shift))))
|
||||||
|
;; Add element to map; level will not change.
|
||||||
|
(if (zero? shift)
|
||||||
|
(unless (eq? root val)
|
||||||
|
(set-transient-intmap-root! map (meet root val)))
|
||||||
|
(let ((root* (writable-branch root edit)))
|
||||||
|
(unless (eq? root root*)
|
||||||
|
(set-transient-intmap-root! map root*))
|
||||||
|
(adjoin! (- i min) shift root*))))
|
||||||
|
(else
|
||||||
|
(let lp ((min min)
|
||||||
|
(shift shift)
|
||||||
|
(root root))
|
||||||
|
(let* ((shift* (+ shift *branch-bits*))
|
||||||
|
(min* (round-down min shift*))
|
||||||
|
(idx (logand (ash (- min min*) (- shift))
|
||||||
|
*branch-mask*))
|
||||||
|
(root* (new-branch edit)))
|
||||||
|
(vector-set! root* idx root)
|
||||||
|
(cond
|
||||||
|
((and (<= min* i) (< i (+ min* (ash 1 shift*))))
|
||||||
|
(set-transient-intmap-min! map min*)
|
||||||
|
(set-transient-intmap-shift! map shift*)
|
||||||
|
(set-transient-intmap-root! map root*)
|
||||||
|
(adjoin! (- i min*) shift* root*))
|
||||||
|
(else
|
||||||
|
(lp min* shift* root*)))))))
|
||||||
|
map)
|
||||||
|
(($ <intmap>)
|
||||||
|
(intmap-add! (transient-intmap map) i val meet))))
|
||||||
|
|
||||||
(define* (intmap-add bs i val #:optional (meet meet-error))
|
(define* (intmap-add bs i val #:optional (meet meet-error))
|
||||||
(define (adjoin i shift root)
|
(define (adjoin i shift root)
|
||||||
(cond
|
(cond
|
||||||
|
@ -145,7 +264,9 @@
|
||||||
(intmap-union (intmap-add empty-intmap i val error) bs error))
|
(intmap-union (intmap-add empty-intmap i val error) bs error))
|
||||||
(else
|
(else
|
||||||
;; Add a new level and try again.
|
;; Add a new level and try again.
|
||||||
(intmap-add (add-level min shift root) i val error))))))
|
(intmap-add (add-level min shift root) i val error))))
|
||||||
|
(($ <transient-intmap>)
|
||||||
|
(intmap-add (persistent-intmap bs) i val meet))))
|
||||||
|
|
||||||
(define (intmap-remove bs i)
|
(define (intmap-remove bs i)
|
||||||
(define (remove i shift root)
|
(define (remove i shift root)
|
||||||
|
@ -175,11 +296,12 @@
|
||||||
(if (eq? root old-root)
|
(if (eq? root old-root)
|
||||||
bs
|
bs
|
||||||
(make-intmap/prune min shift root))))
|
(make-intmap/prune min shift root))))
|
||||||
(else bs)))))
|
(else bs)))
|
||||||
|
(($ <transient-intmap>)
|
||||||
|
(intmap-remove (persistent-intmap bs) i))))
|
||||||
|
|
||||||
(define (intmap-ref bs i)
|
(define (intmap-ref bs i)
|
||||||
(match bs
|
(define (ref min shift root)
|
||||||
(($ <intmap> min shift root)
|
|
||||||
(if (zero? shift)
|
(if (zero? shift)
|
||||||
(and (= i min) root)
|
(and (= i min) root)
|
||||||
(and (<= min i) (< i (+ min (ash 1 shift)))
|
(and (<= min i) (< i (+ min (ash 1 shift)))
|
||||||
|
@ -191,7 +313,13 @@
|
||||||
(let* ((shift (- shift *branch-bits*))
|
(let* ((shift (- shift *branch-bits*))
|
||||||
(idx (logand (ash i (- shift))
|
(idx (logand (ash i (- shift))
|
||||||
*branch-mask*)))
|
*branch-mask*)))
|
||||||
(lp (vector-ref node idx) shift)))))))))))
|
(lp (vector-ref node idx) shift)))))))))
|
||||||
|
(match bs
|
||||||
|
(($ <intmap> min shift root)
|
||||||
|
(ref min shift root))
|
||||||
|
(($ <transient-intmap> min shift root edit)
|
||||||
|
(assert-readable! edit)
|
||||||
|
(ref min shift root))))
|
||||||
|
|
||||||
(define* (intmap-next bs #:optional i)
|
(define* (intmap-next bs #:optional i)
|
||||||
(define (visit-branch node shift i)
|
(define (visit-branch node shift i)
|
||||||
|
@ -205,14 +333,19 @@
|
||||||
(if (zero? shift)
|
(if (zero? shift)
|
||||||
i
|
i
|
||||||
(visit-branch node (- shift *branch-bits*) i))))
|
(visit-branch node (- shift *branch-bits*) i))))
|
||||||
(match bs
|
(define (next min shift root)
|
||||||
(($ <intmap> min shift root)
|
|
||||||
(let ((i (if (and i (< min i))
|
(let ((i (if (and i (< min i))
|
||||||
(- i min)
|
(- i min)
|
||||||
0)))
|
0)))
|
||||||
(and (< i (ash 1 shift))
|
(and (< i (ash 1 shift))
|
||||||
(let ((i (visit-node root shift i)))
|
(let ((i (visit-node root shift i)))
|
||||||
(and i (+ min i))))))))
|
(and i (+ min i))))))
|
||||||
|
(match bs
|
||||||
|
(($ <intmap> min shift root)
|
||||||
|
(next min shift root))
|
||||||
|
(($ <transient-intmap> min shift root edit)
|
||||||
|
(assert-readable! edit)
|
||||||
|
(next min shift root))))
|
||||||
|
|
||||||
(define* (intmap-prev bs #:optional i)
|
(define* (intmap-prev bs #:optional i)
|
||||||
(define (visit-branch node shift i)
|
(define (visit-branch node shift i)
|
||||||
|
@ -225,14 +358,19 @@
|
||||||
(if (zero? shift)
|
(if (zero? shift)
|
||||||
i
|
i
|
||||||
(visit-branch node (- shift *branch-bits*) i))))
|
(visit-branch node (- shift *branch-bits*) i))))
|
||||||
(match bs
|
(define (prev min shift root)
|
||||||
(($ <intmap> min shift root)
|
|
||||||
(let* ((i (if (and i (< i (+ min (ash 1 shift))))
|
(let* ((i (if (and i (< i (+ min (ash 1 shift))))
|
||||||
(- i min)
|
(- i min)
|
||||||
(1- (ash 1 shift)))))
|
(1- (ash 1 shift)))))
|
||||||
(and (<= 0 i)
|
(and (<= 0 i)
|
||||||
(let ((i (visit-node root shift i)))
|
(let ((i (visit-node root shift i)))
|
||||||
(and i (+ min i))))))))
|
(and i (+ min i))))))
|
||||||
|
(match bs
|
||||||
|
(($ <intmap> min shift root)
|
||||||
|
(prev min shift root))
|
||||||
|
(($ <transient-intmap> min shift root edit)
|
||||||
|
(assert-readable! edit)
|
||||||
|
(prev min shift root))))
|
||||||
|
|
||||||
(define (intmap-fold f map seed)
|
(define (intmap-fold f map seed)
|
||||||
(define (visit-branch node shift min seed)
|
(define (visit-branch node shift min seed)
|
||||||
|
@ -259,7 +397,9 @@
|
||||||
(cond
|
(cond
|
||||||
((not root) seed)
|
((not root) seed)
|
||||||
((zero? shift) (f min root seed))
|
((zero? shift) (f min root seed))
|
||||||
(else (visit-branch root shift min seed))))))
|
(else (visit-branch root shift min seed))))
|
||||||
|
(($ <transient-intmap>)
|
||||||
|
(intmap-fold f (persistent-intmap map) seed))))
|
||||||
|
|
||||||
(define* (intmap-union a b #:optional (meet meet-error))
|
(define* (intmap-union a b #:optional (meet meet-error))
|
||||||
;; Union A and B from index I; the result will be fresh.
|
;; Union A and B from index I; the result will be fresh.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue