chibi-scheme/lib/chibi/iset/constructors.scm

316 lines
10 KiB
Scheme

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Utilities for constructing and joining isets.
(define bits-thresh 128) ; within 128 we join into a bitmap
(define bits-max 512) ; don't make bitmaps larger than this
(define (bit-set n index)
(bitwise-ior n (arithmetic-shift 1 index)))
(define (bit-clear n index)
(if (bit-set? index n)
(- n (arithmetic-shift 1 index))
n))
(define (iset . args)
(list->iset args))
(define (list->iset! ls iset)
(for-each (lambda (i) (iset-adjoin1! iset i)) ls)
iset)
(define (list->iset ls . opt)
(list->iset! ls (if (pair? opt) (iset-copy (car opt)) (make-iset))))
(define (iset-copy iset)
(and iset
(%make-iset
(iset-start iset)
(iset-end iset)
(iset-bits iset)
(iset-copy (iset-left iset))
(iset-copy (iset-right iset)))))
(define (iset-copy-node iset)
(%make-iset (iset-start iset) (iset-end iset) (iset-bits iset) #f #f))
(define (iset-max-end iset)
(cond ((iset-right iset) => iset-max-end)
(else (iset-end iset))))
(define (iset-min-start iset)
(cond ((iset-left iset) => iset-min-start)
(else (iset-start iset))))
(define (iset-insert-left! iset new)
(let ((left (iset-left iset)))
(if (and left (< (iset-end new) (iset-start left)))
(iset-right-set! new left)
(iset-left-set! new left)))
(iset-left-set! iset new))
(define (iset-insert-right! iset new)
(let ((right (iset-right iset)))
(if (and right (< (iset-end new) (iset-start right)))
(iset-right-set! new right)
(iset-left-set! new right)))
(iset-right-set! iset new))
(define (range->bits start end)
(- (arithmetic-shift 1 (+ 1 (- end start))) 1))
(define (iset-squash-bits! iset)
(let ((bits (iset-bits iset)))
(if (and bits (= bits (range->bits (iset-start iset) (iset-end iset))))
(iset-bits-set! iset #f))))
(define (iset-adjoin1! iset n)
(cond
((iset-empty? iset)
(iset-start-set! iset n)
(iset-end-set! iset n)
(iset-bits-set! iset #f))
(else
(let ((start (iset-start iset))
(end (iset-end iset))
(bits (iset-bits iset)))
(cond
((< n start)
(let ((s-diff (- start n)))
(if (let* ((left (iset-left iset))
(m-end (and left (iset-max-end left))))
(and m-end
(or (<= n m-end)
(< (- n m-end) s-diff))))
(iset-adjoin1! (iset-left iset) n)
(cond
((and (< s-diff bits-thresh)
(< (- end n) bits-max))
(iset-start-set! iset n)
(let ((bits2 (arithmetic-shift (or bits (range->bits start end))
s-diff)))
(iset-bits-set! iset (+ bits2 1))
(iset-squash-bits! iset)))
(else (iset-insert-left! iset (make-iset n)))))))
((> n end)
(let ((e-diff (- n end)))
(if (let* ((right (iset-right iset))
(m-start (and right (iset-min-start right))))
(and m-start
(or (>= n m-start)
(> (- n m-start) e-diff))))
(iset-adjoin1! (iset-right iset) n)
(cond
((and (< e-diff bits-thresh)
(< (- n start) bits-max))
(iset-end-set! iset n)
(iset-bits-set! iset (bit-set (or bits (range->bits start end))
(- n start)))
(iset-squash-bits! iset))
(else (iset-insert-right! iset (make-iset n)))))))
(bits
(iset-bits-set! iset (bit-set (iset-bits iset) (- n start)))
(iset-squash-bits! iset)))))))
(define (iset-adjoin-node! a b)
(cond
((iset-empty? a)
(iset-start-set! a (iset-start b))
(iset-end-set! a (iset-end b))
(iset-bits-set! a (iset-bits b)))
((not (iset-empty? b))
(let ((a-start (iset-start a))
(a-end (iset-end a))
(a-bits (iset-bits a))
(b-start (iset-start b))
(b-end (iset-end b))
(b-bits (iset-bits b)))
(cond
;; aaaa...
;; ...bbbb
((< b-end a-start)
(let ((near-diff (- a-start b-end))
(start-diff (- a-start b-start))
(far-diff (- a-end b-start)))
(if (let* ((left (iset-left a))
(m-end (and left (iset-max-end left))))
(and m-end
(or (< b-end m-end)
(< (- b-end m-end) near-diff))))
(iset-adjoin-node! (iset-left a) b)
(cond
((and (< near-diff bits-thresh)
(< far-diff bits-max))
(let ((bits (arithmetic-shift
(or a-bits (range->bits a-start a-end))
start-diff))
(lo-bits (or b-bits (range->bits b-start b-end))))
(iset-start-set! a b-start)
(iset-bits-set! a (bitwise-ior bits lo-bits))
(iset-squash-bits! a)))
(else (iset-insert-left! a (iset-copy-node b)))))))
;; ...aaaa
;; bbbb...
((> b-start a-end)
(let ((near-diff (- b-start a-end))
(start-diff (- b-start a-start))
(far-diff (- b-end a-start)))
(if (let* ((right (iset-right a))
(m-start (and right (iset-min-start right))))
(and m-start
(or (> b-start m-start)
(> (- b-start m-start) near-diff))))
(iset-adjoin-node! (iset-right a) b)
(cond
((and (< near-diff bits-thresh)
(< far-diff bits-max))
(iset-end-set! a b-end)
(iset-bits-set!
a
(bitwise-ior
(or a-bits (range->bits a-start a-end))
(arithmetic-shift
(or b-bits (range->bits b-start b-end))
start-diff)))
(iset-squash-bits! a))
(else (iset-insert-right! a (iset-copy-node b)))))))
;; aaaa...
;; bbbb...
((> b-start a-start)
(iset-end-set! a (max a-end b-end))
(cond
((or a-bits b-bits)
(iset-bits-set!
a
(bitwise-ior
(or a-bits (range->bits a-start a-end))
(arithmetic-shift
(or b-bits (range->bits b-start b-end))
(- b-start a-start))))
(iset-squash-bits! a))))
;; aaaa...
;; bbbb...
((< b-start a-start)
(iset-start-set! a b-start)
(iset-end-set! a (max a-end b-end))
(cond
((or a-bits b-bits)
(iset-bits-set!
a
(bitwise-ior
(arithmetic-shift
(or a-bits (range->bits a-start a-end))
(- a-start b-start))
(or b-bits (range->bits b-start b-end))))
(iset-squash-bits! a))))
;; aaaa...
;; bbbb...
(else
(iset-end-set! a (max a-end b-end))
(cond
((or a-bits b-bits)
(iset-bits-set!
a
(bitwise-ior
(or a-bits (range->bits a-start a-end))
(or b-bits (range->bits b-start b-end))))
(iset-squash-bits! a)))))))))
(define (iset-adjoin! iset . ls)
(list->iset! ls iset))
(define (iset-adjoin iset . ls)
(list->iset ls iset))
;; delete directly in this node
(define (%iset-delete1! iset n)
(let ((start (iset-start iset))
(end (iset-end iset))
(bits (iset-bits iset)))
(cond
(bits
(iset-bits-set! iset (bit-clear bits (- n start))))
((= n start)
(if (= n end)
(iset-bits-set! iset 0)
(iset-start-set! iset (+ n 1))))
((= n end)
(iset-end-set! iset (- n 1)))
(else
(iset-end-set! iset (- n 1))
(iset-insert-right! iset (make-iset (+ n 1) end))))))
(define (iset-delete1! iset n)
(let lp ((is iset))
(let ((start (iset-start is)))
(if (< n start)
(let ((left (iset-left is)))
(if left (lp left)))
(let ((end (iset-end is)))
(if (> n end)
(let ((right (iset-right is)))
(if right (lp right)))
(%iset-delete1! is n)))))))
(define (iset-delete! iset . args)
(for-each (lambda (i) (iset-delete1! iset i)) args)
iset)
(define (iset-delete iset . args)
(apply iset-delete! (iset-copy iset) args))
(define (iset-map proc iset)
(iset-fold (lambda (i is) (iset-adjoin! is i)) (make-iset) iset))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; High-level set operations.
;;
;; Union is optimized to work at the node level. Intersection and
;; difference iterate over individual elements and so have a lot of
;; room for improvement, at the expense of the complexity of
;; iset-adjoin-node!.
(define (iset-union2! a b)
(iset-for-each-node
(lambda (is)
(iset-adjoin-node! a is))
b))
(define (iset-union! . args)
(let* ((a (and (pair? args) (car args)))
(b (and (pair? args) (pair? (cdr args)) (cadr args))))
(cond
(b
(iset-union2! a b)
(apply iset-union! a (cddr args)))
(a a)
(else (make-iset)))))
(define (iset-union . args)
(if (null? args)
(make-iset)
(apply iset-union! (iset-copy (car args)) (cdr args))))
(define (iset-intersection! a . args)
(let ((b (and (pair? args) (car args))))
(cond
(b
(iset-for-each
(lambda (i) (if (not (iset-contains? b i)) (iset-delete1! a i)))
a)
(apply iset-intersection! a (cdr args)))
(else a))))
(define (iset-intersection a . args)
(apply iset-intersection! (iset-copy a) args))
(define (iset-difference! a . args)
(if (null? args)
a
(begin
(iset-for-each (lambda (i) (iset-delete1! a i)) (car args))
(apply iset-difference! a (cdr args)))))
(define (iset-difference a . args)
(apply iset-difference! (iset-copy a) args))