mirror of
https://github.com/ashinn/chibi-scheme.git
synced 2025-05-19 21:59:17 +02:00
They can be close()d explicitly with close-file-descriptor, and will close() on gc, but only explicitly closing the last port on them will close the fileno. Notably needed for network sockets where we open separate input and output ports on the same socket.
316 lines
10 KiB
Scheme
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))
|