;;; Procedure: ;;; make-queue ;;; Parameters: ;;; [None] ;;; Produces: ;;; queue, a procedure ;;; Preconditions: ;;; [None] ;;; Postconditions: ;;; (1) queue initially represents the empty queue. ;;; (2) Whenever queue is invoked with the argument :empty?, it reports ;;; whether it is empty. ;;; (3) When queue has been invoked with the first argument :enqueue! and ;;; a second argument, say new-value, new-value is at the rear, and ;;; all other values in the queue are in front of it, in order by ;;; time of enqueuing. ;;; (4) When queue has been invoked with the argument :dequeue!, it ;;; returns the longest-enqueued value, the one at the front, and ;;; retains all other values, in order by time of enqueuing. ;;; (5) When queue is invoked with the argument :front, it returns the ;;; value at the front (available for dequeuing). ;;; (6) When queue is invoked with the argument :size, it returns the ;;; number of values in the queue. ;;; (7) It is an error to give queue any other argument when invoking it. ;;; (8) When queue is invoked with the first argument :empty?, :dequeue!, ;;; :front, or :size, it is an error to give it two or more arguments. ;;; (9) When queue is invoked with the first argument :enqueue!, it is an ;;; error to give it only one argument or three or more. (define make-queue (lambda () (let ((parts (vector null null 0))) ; front, rear, size (lambda (message . arguments) (cond ((eq? message ':empty?) (if (null? arguments) (zero? (vector-ref parts 2)) (error 'queue:empty? "no arguments are permitted"))) ((eq? message ':enqueue!) (cond ((null? arguments) (error 'queue:enqueue! " an argument is required")) ((not (null? (cdr arguments))) (error 'queue:enqueue! "only one argument permitted")) (else ; Place the new value on the rear of the queue. (vector-set! parts 1 (cons (car arguments) (vector-ref parts 1))) ; Increment size. (vector-set! parts 2 (+ 1 (vector-ref parts 2)))))) ((eq? message ':dequeue!) (cond ((not (null? arguments)) (error "queue:dequeue!: no argument is permitted")) ((zero? (vector-ref parts 2)) (error "queue:dequeue!: the queue is empty")) (else ; Shove stuff from rear to front if necessary. (if (null? (vector-ref parts 0)) (begin (vector-set! parts 0 (reverse (vector-ref parts 1))) (vector-set! parts 1 null))) ; Recover the first element of the queue. (let ((removed (car (vector-ref parts 0)))) ; Remove the element to be dequeued. (vector-set! parts 0 (cdr (vector-ref parts 0))) ; Decrement size. (vector-set! parts 2 (- (vector-ref parts 2) 1)) ; Return that which we removed removed)))) ((eq? message ':front) (cond ((not (null? arguments)) (error "queue:front: no argument is permitted")) ((zero? (vector-ref parts 2)) (error "queue:front: the queue is empty")) (else ; Shove stuff from rear to front if necessary. (if (null? (vector-ref vec 0)) (begin (vector-set! parts 0 (reverse (vector-ref parts 1))) (vector-set! parts 1 null))) ; Return the appropriate element (car (vector-ref parts 0))))) ((eq? message ':size) (if (null? arguments) (vector-ref parts 2) (error "queue:size: no argument is permitted"))) (else (error 'queue "unrecognized message")))))))