(define-syntax define-macro (syntax-rules () ((_ (name . llist) body ...) (define-syntax name (lambda (x r c) (apply (lambda llist body ...) (cdr x))))) ((_ name . body) (define-syntax name (lambda (x r c) (cdr x)))))) (define-macro (define-rbtree rbtree-init! node->rbtree lookup ; may be #f tree-fold ; may be #f tree-for-each ; may be #f insert! remove! reposition! empty? singleton? match? ; may be #f iff lookup is #f keyrbtree node) (or (,color node) (,color (,parent node)))) ,@(if lookup `((define (,lookup rbtree key) (let loop ((node (,left (,node->rbtree rbtree)))) (if (eq? rbtree node) #f (cond ((,match? key node) node) ((,keyrbtree rbtree))))) '()) ,@(if tree-for-each `((define (,tree-for-each procedure rbtree) (let loop ((node (,left (,node->rbtree rbtree)))) (or (eq? rbtree node) (begin (procedure node) (loop (,left node)) (loop (,right node))))))) '()) (define (,insert! rbtree node) (define (fixup!) (let loop ((x node)) (let ((parent-x (,parent x))) (if (,(red?) parent-x) (let ((parent-parent-x (,parent parent-x))) (if (eq? parent-x (,left parent-parent-x)) ,(insert-body left (rotate-left!) right (rotate-right!)) ,(insert-body right (rotate-right!) left (rotate-left!))))))) (,(blacken! 'rbtree) (,left rbtree)) #f) (define (insert-left! left-x x) (if (eq? left-x rbtree) (begin (,left-set! x node) (,parent-set! node x) ;; check if leftmost must be updated ,@(if leftmost `((if (eq? x (,leftmost rbtree)) (,leftmost-set! rbtree node))) `()) (fixup!)) ,(insert-below! 'left-x))) (define (insert-right! right-x x) (if (eq? right-x rbtree) (begin (,right-set! x node) (,parent-set! node x) ;; check if rightmost must be updated ,@(if rightmost `((if (eq? x (,rightmost rbtree)) (,rightmost-set! rbtree node))) `()) (fixup!)) ,(insert-below! 'right-x))) (,(reden!) node) (,left-set! node rbtree) (,right-set! node rbtree) (insert-left! (,left rbtree) rbtree) (,parent-set! rbtree rbtree) node) (define (,remove! node) (let ((rbtree (,node->rbtree node))) (define (fixup! parent-node node) (cond ((or (eq? parent-node rbtree) (,(red?) node)) (,(blacken! 'rbtree) node)) ((eq? node (,left parent-node)) ,(remove-body left (rotate-left!) right (rotate-right!))) (else ,(remove-body right (rotate-right!) left (rotate-left!))))) (let ((parent-node (,parent node)) (left-node (,left node)) (right-node (,right node))) (,parent-set! node #f) ;; to avoid leaks (,left-set! node #f) (,right-set! node #f) (cond ((eq? left-node rbtree) ;; check if leftmost must be updated ,@(if leftmost `((if (eq? node (,leftmost rbtree)) (,leftmost-set! rbtree (if (eq? right-node rbtree) parent-node right-node)))) `()) (,parent-set! right-node parent-node) (,(update-parent!) parent-node node right-node) (if (,(black? 'rbtree) node) (begin (,(reden!) node) ;; to avoid leaks (fixup! parent-node right-node)))) ((eq? right-node rbtree) ;; check if rightmost must be updated ,@(if rightmost `((if (eq? node (,rightmost rbtree)) (,rightmost-set! rbtree left-node))) `()) (,parent-set! left-node parent-node) (,(update-parent!) parent-node node left-node) ;; At this point we know that the node is black. ;; This is because the right child is nil and the ;; left child is red (if the left child was black ;; the tree would not be balanced) (,(reden!) node) ;; to avoid leaks (fixup! parent-node left-node)) (else (let loop ((x right-node) (parent-x node)) (let ((left-x (,left x))) (if (eq? left-x rbtree) (begin (,(exchange-color!) x node) (,parent-set! left-node x) (,left-set! x left-node) (,parent-set! x parent-node) (,(update-parent!) parent-node node x) (if (eq? x right-node) (if (,(black? 'rbtree) node) (begin (,(reden!) node) ;; to avoid leaks (fixup! x (,right x)))) (let ((right-x (,right x))) (,parent-set! right-x parent-x) (,left-set! parent-x right-x) (,parent-set! right-node x) (,right-set! x right-node) (if (,(black? 'rbtree) node) (begin (,(reden!) node) ;; to avoid leaks (fixup! parent-x right-x)))))) (loop left-x x))))))) (,parent-set! rbtree rbtree))) (define (,reposition! node) (let* ((rbtree (,node->rbtree node)) (predecessor-node (,(neighbor left right) node rbtree)) (successor-node (,(neighbor right left) node rbtree))) (if (or (and (not (eq? predecessor-node rbtree)) (,before? node predecessor-node)) (and (not (eq? successor-node rbtree)) (,before? successor-node node))) (begin (,remove! node) (,insert! rbtree node))))) (define (,empty? rbtree) (eq? rbtree (,left rbtree))) (define (,singleton? rbtree) (let ((root (,left rbtree))) (and (not (eq? root rbtree)) (eq? (,left root) rbtree) (eq? (,right root) rbtree))))))