(define-struct set-cell
(next
previous
priority
item)
#:mutable)
(define-values (struct:set
set-constructor
set?
set-field-ref
set-set-field!)
(make-struct-type 'set #f 4 0))
(define set-variable-n
(make-struct-field-accessor set-field-ref 0 'variable-n))
(define set-set-variable-n!
(make-struct-field-mutator set-set-field! 0 'variable-n))
(define (set-n set)
(variable-value (set-field-ref set 0)))
(define (set-set-n! set n)
(set-variable-value! (set-field-ref set 0) n))
(define set-first-cell
(make-struct-field-accessor set-field-ref 1 'first-cell))
(define set-set-first-cell!
(make-struct-field-mutator set-set-field! 1 'first-cell))
(define set-last-cell
(make-struct-field-accessor set-field-ref 2 'last-cell))
(define set-set-last-cell!
(make-struct-field-mutator set-set-field! 2 'last-cell))
(define set-type
(make-struct-field-accessor set-field-ref 3 'type))
(define set-set-type!
(make-struct-field-mutator set-set-field! 3 'type))
(define make-set
(case-lambda
((type)
(set-constructor (make-variable 0) '() '() type))
(()
(make-set '#:fifo))))
(define (set-empty? set)
(= (set-n set) 0))
(define (set-first set)
(when (set-empty? set)
(error 'set-first
"set is empty"))
(set-cell-item (set-first-cell set)))
(define (set-last set)
(when (set-empty? set)
(error 'set-last
"set is empty"))
(set-cell-item (set-last-cell set)))
(define (set-for-each-cell set proc)
(let loop ((cell (set-first-cell set)))
(if (not (null? cell))
(let ((next (set-cell-next cell)))
(proc cell)
(loop next))
(void))))
(define (set-for-each set proc)
(let loop ((cell (set-first-cell set)))
(if (not (null? cell))
(let ((next (set-cell-next cell))
(item (set-cell-item cell)))
(proc item)
(loop next))
(void))))
(define (set-find-cell set item)
(let/ec exit
(set-for-each-cell set
(lambda (cell)
(when (eq? (set-cell-item cell) item)
(exit cell))))
#f))
(define (set-insert-cell-first! set cell)
(set-set-n! set (+ (set-n set) 1))
(set-set-cell-next! cell (set-first-cell set))
(set-set-first-cell! set cell)
(set-set-cell-previous! cell '())
(if (null? (set-cell-next cell))
(set-set-last-cell! set cell)
(set-set-cell-previous! (set-cell-next cell) cell)))
(define (set-insert-first! set item)
(set-insert-cell-first! set (make-set-cell '() '() #f item)))
(define (set-insert-cell-last! set cell)
(set-set-n! set (+ (set-n set) 1))
(set-set-cell-previous! cell (set-last-cell set))
(set-set-last-cell! set cell)
(set-set-cell-next! cell '())
(if (null? (set-cell-previous cell))
(set-set-first-cell! set cell)
(set-set-cell-next! (set-cell-previous cell) cell)))
(define (set-insert-last! set item)
(set-insert-cell-last! set (make-set-cell '() '() #f item)))
(define (set-insert-cell-priority! set cell)
(set-set-n! set (+ (set-n set) 1))
(let ((cells (set-first-cell set)))
(let loop ()
(when (and (not (null? cells))
(<= (set-cell-priority cell)
(set-cell-priority (car cells))))
(set! cells (cdr cells))
(loop)))
(set-set-cell-next! cell (car cells))
(set-set-cell-previous! cell (if cells
(set-cell-previous (car cells))
(set-last-cell set)))
(when (null? (set-cell-next cell))
(set-set-last-cell! set cell))
(when (null? (set-cell-previous cell))
(set-set-first-cell! set cell))))
(define (set-insert-priority! set item priority)
(set-insert-cell-priority! set (make-set-cell '() '() priority item)))
(define (set-remove-cell! set cell)
(set-set-n! set (- (set-n set) 1))
(if (null? (set-cell-previous cell))
(set-set-first-cell! set (set-cell-next cell))
(set-set-cell-next! (set-cell-previous cell)
(set-cell-next cell)))
(if (null? (set-cell-next cell))
(set-set-last-cell! set (set-cell-previous cell))
(set-set-cell-previous! (set-cell-next cell)
(set-cell-previous cell)))
(set-set-cell-next! cell '())
(set-set-cell-previous! cell '()))
(define (set-remove-item! set item)
(let ((cell (set-find-cell set item)))
(set-remove-cell! set cell)
cell))
(define set-remove-first-cell!
(case-lambda
((set)
(when (set-empty? set)
(error 'set-remove-first-cell!
"set is empty"))
(let ((cell (set-first-cell set)))
(set-remove-cell! set cell)
cell))
((set error-thunk)
(if (set-empty? set)
((error-thunk))
(set-remove-first-cell! set)))))
(define set-remove-first!
(case-lambda
((set)
(when (set-empty? set)
(error 'set-remove-first!
"set is empty"))
(set-cell-item (set-remove-first-cell! set)))
((set error-thunk)
(if (set-empty? set)
((error-thunk))
(set-remove-first! set)))))
(define set-remove-last-cell!
(case-lambda
((set)
(when (set-empty? set)
(error 'set-remove-last-cell!
"set is empty"))
(let ((cell (set-last-cell set)))
(set-remove-cell! set cell)
cell))
((set error-thunk)
(if (set-empty? set)
((error-thunk))
(set-remove-last-cell! set)))))
(define set-remove-last!
(case-lambda
((set)
(when (set-empty? set)
(error 'set-remove-last!
"set is empty"))
(set-cell-item (set-remove-last-cell! set)))
((set error-thunk)
(if (set-empty? set)
((error-thunk))
(set-remove-last! set)))))
(define set-insert!
(case-lambda
((set item priority)
(case (set-type set)
((#:fifo)
(set-insert-last! set item))
((#:lifo)
(set-insert-first! set item))
((#:priority)
(set-insert-priority! set item priority))
(else
(error 'set-insert! "unknown set type ~a" (set-type set)))))
((set item)
(case (set-type set)
((#:fifo)
(set-insert-last! set item))
((#:lifo)
(set-insert-first! set item))
((#:priority)
(set-insert-priority! set item 100))
(else
(error 'set-insert! "unknown set type ~a" (set-type set)))))))
(define set-remove!
(case-lambda
((set item)
(set-remove-item! set item))
((set)
(set-remove-first! set))))