1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
;;;-*- Mode: Lisp; Package: containers -*-
(in-package #:containers)
;;; Abstract Queue interface
;;;
;;; supports: enqueue (insert-item), dequeue (delete-first), empty!,
;;; size, empty-p, first-element
(defclass* abstract-queue (initial-contents-mixin ordered-container-mixin)
())
(defmethod enqueue ((queue abstract-queue) item)
(insert-item queue item))
(defmethod dequeue ((queue abstract-queue))
(delete-first queue))
(defmethod empty! ((q abstract-queue))
;; Dequeue items until the queue is empty. Inefficient, but always works.
(do ()
((empty-p q) q)
(delete-first q))
(values))
(defmethod first-element :before ((q abstract-queue))
(error-if-queue-empty q "Tried to examine first-element from an empty queue."))
(defmethod delete-first :before ((q abstract-queue))
(error-if-queue-empty q "Tried to dequeue from an empty queue."))
(defmethod error-if-queue-empty ((q abstract-queue) &optional
(message "Cannot work with an empty queue")
&rest rest)
(when (empty-p q)
(error message rest)))
;;; Priority Queues on 'arbitrary' containers
;;;
;;; The underlying container must support: insert-item, first-element
;;; delete-item, empty-p, empty!, size, find-item,
;;; delete-item and delete-item-if
(defclass* priority-queue-on-container (iteratable-container-mixin
sorted-container-mixin
findable-container-mixin
concrete-container
abstract-queue)
((container nil r))
(:default-initargs
:container-type 'binary-search-tree))
(defmethod initialize-instance :around
((object priority-queue-on-container) &rest args
&key container-type &allow-other-keys)
(remf args :container-type)
(remf args :initial-contents)
(setf (slot-value object 'container)
(apply #'make-container container-type args))
(call-next-method))
(defmethod insert-item ((q priority-queue-on-container) item)
(insert-item (container q) item))
(defmethod delete-first ((q priority-queue-on-container))
(let ((m (first-node (container q))))
(delete-node (container q) m)
(element m)))
(defmethod empty-p ((q priority-queue-on-container))
(empty-p (container q)))
(defmethod empty! ((q priority-queue-on-container))
(empty! (container q))
(values))
(defmethod size ((q priority-queue-on-container))
(size (container q)))
(defmethod first-element ((q priority-queue-on-container))
(first-element (container q)))
(defmethod (setf first-element) (value (q priority-queue-on-container))
(setf (first-element (container q)) value))
(defmethod find-item ((q priority-queue-on-container) (item t))
(let ((node (find-item (container q) item)))
(when node (element node))))
(defmethod find-node ((q priority-queue-on-container) (item t))
(find-node (container q) item))
(defmethod find-element ((q priority-queue-on-container) (item t))
(find-element (container q) item))
(defmethod delete-item ((q priority-queue-on-container) (item t))
(delete-item (container q) item))
(defmethod delete-node ((q priority-queue-on-container) (item t))
(delete-node (container q) item))
(defmethod delete-element ((q priority-queue-on-container) (item t))
(delete-element (container q) item))
(defmethod delete-item-if (test (q priority-queue-on-container))
(delete-item-if test (container q)))
(defmethod iterate-nodes ((q priority-queue-on-container) fn)
(iterate-nodes (container q) fn))
(defmethod iterate-elements ((q priority-queue-on-container) fn)
(iterate-elements (container q) fn))
;;; Standard no frills queue
(defclass* basic-queue (abstract-queue iteratable-container-mixin
concrete-container)
((queue nil :accessor queue-queue)
(indexer nil :accessor queue-header))
(:documentation "A simple FIFO queue implemented as a list with extra bookkeeping for efficiency."))
;; Some semantically helpful functions
(defun front-of-queue (queue)
(car (queue-header queue)))
(defun front-of-queue! (queue new)
(setf (car (queue-header queue)) new))
(defsetf front-of-queue front-of-queue!)
(defun tail-of-queue (queue)
(cdr (queue-header queue)))
(defun tail-of-queue! (queue new)
(setf (cdr (queue-header queue)) new))
(defsetf tail-of-queue tail-of-queue!)
(eval-when (:compile-toplevel)
(proclaim '(inline front-of-queue front-of-queue!))
(proclaim '(inline tail-of-queue tail-of-queue!)))
(defmethod insert-item ((q basic-queue) (item t))
"Add an item to the queue."
(let ((new-item (list item)))
(cond ((empty-p q)
(setf (queue-queue q) new-item
(queue-header q) (cons (queue-queue q) (queue-queue q))))
(t
(setf (cdr (tail-of-queue q)) new-item
(tail-of-queue q) new-item))))
q)
(defmethod delete-first ((q basic-queue))
(let ((result (front-of-queue q)))
(setf (front-of-queue q) (cdr result)
result (first result))
;; reset things when I'm empty
(when (null (front-of-queue q))
(empty! q))
result))
(defmethod empty-p ((q basic-queue))
(null (queue-header q)))
(defmethod iterate-nodes ((q basic-queue) fn)
(let ((start (front-of-queue q)))
(mapc fn start))
(values q))
(defmethod size ((q basic-queue))
;;??slow
(if (empty-p q)
0
(length (front-of-queue q))))
(defmethod first-element ((q basic-queue))
"Returns the first item in a queue without changing the queue."
(car (front-of-queue q)))
(defmethod (setf first-element) (value (q basic-queue))
"Returns the first item in a queue without changing the queue."
(setf (car (front-of-queue q)) value))
(defmethod empty! ((q basic-queue))
"Empty a queue of all contents."
(setf (queue-queue q) nil
(queue-header q) nil)
(values))
(defmethod delete-item ((queue basic-queue) item)
(unless (empty-p queue)
(cond ((eq item (first-element queue))
(delete-first queue))
((eq item (car (tail-of-queue queue)))
;; expensive special case...
(setf (queue-queue queue) (remove item (queue-queue queue))
(front-of-queue queue) (queue-queue queue)
(tail-of-queue queue) (last (front-of-queue queue))))
(t
(setf (queue-queue queue) (delete item (queue-queue queue)))))))
|