forked from franzinc/clim2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathqueue.lisp
220 lines (176 loc) · 6.22 KB
/
queue.lisp
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Package: CLIM-UTILS; Base: 10; Lowercase: Yes -*-
;; See the file LICENSE for the full license governing this code.
;;
;;;
;;; Copyright (c) 1989 by Xerox Corporations. All rights reserved.
;;;
;;; This code was taken from the ARIA code which is copyrighted by MCC, Xerox,
;;; and Franz, Inc. It was further modified by Ramana Rao.
;;;
(in-package :clim-utils)
;;;
;;;
;;; Implementation of simple variable length queues - fifo & lifo
;;;
;;;
(defclass queue ()
((head :initform nil)
(tail :initform nil)
(free-list :initform nil)))
(define-constructor make-queue queue () )
(defmacro queue-head (queue)
`(slot-value ,queue 'head))
(defmacro queue-tail (queue)
`(slot-value ,queue 'tail))
(defmethod print-object ((queue queue) stream)
"Print a queue object"
(print-unreadable-object (queue stream :type t :identity t)
(format stream "element-type: ~A" (queue-contents-type queue))))
;;;
;;; Utility Macros
;;;
(defmacro get-free-cons (queue)
;; get the first cons off the free list or a new cons if none
`(rplacd
(prog1
(or
(slot-value ,queue 'free-list)
(cons nil nil))
(setf (slot-value ,queue 'free-list)
(cdr (slot-value ,queue 'free-list))))
nil))
(defmacro free-cons (queue cons)
;; add a cons cell to the list of free cons cells
`(prog1
(cdr ,cons)
(rplacd ,cons (slot-value ,queue 'free-list))
(rplaca ,cons nil)
(setf (slot-value ,queue 'free-list) ,cons)))
;;;
;;; external queue operations
;;;
(defmethod queue-contents-type ((queue queue))
"return t to indicate that a simple queue stores anything"
t)
(defmethod queue-size ((queue queue))
"return nil to indicate that this queue is variable length"
nil)
(defmethod queue-length ((queue queue))
"Return an integer indicating the number of items on this queue"
(length (queue-head queue)))
(defmethod queue-contents-list ((queue queue))
"return a list of all the queue contents"
(copy-list (queue-head queue)))
(defgeneric map-over-queue (function queue)
(declare (dynamic-extent function)))
(defmethod map-over-queue (function (queue queue))
(declare (dynamic-extent function))
(mapc function (queue-head queue)))
(defmethod queue-next ((queue queue))
"return the head element of the queue
without modifying the queue"
(car (queue-head queue)))
(defmethod queue-last ((queue queue))
"return the last element of the queue
without modifying the queue"
(car (queue-tail queue)))
(defmethod queue-flush ((queue queue))
"delete all elements from the queue"
(do ()
((null (queue-head queue)))
(setf (queue-head queue) (free-cons queue (queue-head queue))))
(setf (queue-tail queue) nil))
(defmethod queue-empty-p ((queue queue))
(null (queue-head queue)))
(defmethod queue-full-p ((queue queue))
"return nil to indicate that varibale length queues are never empty"
nil)
(defmethod queue-put ((queue queue) item)
"put a new element at the tail of the fifo queue
or at the head of the lifo queue"
(let ((new-item (rplaca (get-free-cons queue) item)))
(if (queue-empty-p queue)
(psetf (queue-head queue) new-item
(queue-tail queue) new-item)
(progn
(rplacd (queue-tail queue) new-item)
(setf (queue-tail queue) new-item)))
queue))
(defmethod queue-get ((queue queue) &optional default)
"return the element at the head of the queue
deleteing it from the queue"
(if (queue-empty-p queue)
default
(prog1
(queue-next queue)
(setf (queue-head queue) (free-cons queue (queue-head queue))))))
(defmethod queue-unget ((queue queue) item)
;;--- Eventually this will check to see that the item being ungotten
;;--- is the same as the last gotten item.
(let ((new-item (rplaca (get-free-cons queue) item)))
(if (queue-empty-p queue)
(psetf (queue-head queue) new-item
(queue-tail queue) new-item)
(psetf (cdr new-item) (queue-head queue)
(queue-head queue) new-item))))
(defmethod queue-push ((queue queue) item)
"put a new element at the tail of the fifo queue
or at the head of the lifo queue"
(let ((new-item (rplaca (get-free-cons queue) item)))
(if (queue-empty-p queue)
(setf (queue-head queue) new-item
(queue-tail queue) new-item)
(progn
(rplacd new-item (queue-head queue))
(setf (queue-head queue) new-item)))
queue))
(defmethod queue-pop ((queue queue) &optional default)
"return the element at the head of the queue
deleteing it from the queue"
(if (queue-empty-p queue)
default
(prog1
(queue-next queue)
(setf (queue-head queue) (free-cons queue (queue-head queue))))))
;;;
;;; Locking Queues
;;;
(defclass locking-queue (queue)
((lock-place :initform (make-lock "a queue lock"))))
(define-constructor make-locking-queue queue () )
(defmacro with-queue-locked (queue &body body)
#+ccl (declare (ignore queue))
#+ccl `(progn ,@body)
#-ccl
`(with-slots (lock-place) ,queue
(with-lock-held (lock-place "Queue lock")
,@body)))
(defmethod queue-length ((queue locking-queue))
(with-queue-locked queue
(call-next-method)))
(defmethod queue-contents-list ((queue locking-queue))
(with-queue-locked queue
(call-next-method)))
(defmethod map-over-queue (function (queue locking-queue))
#-aclpc (declare (ignore function))
(with-queue-locked queue
(call-next-method)))
(defmethod queue-flush ((queue locking-queue))
(with-queue-locked queue
(call-next-method)))
(defmethod queue-put ((queue locking-queue) item)
#-aclpc (declare (ignore item))
(with-queue-locked queue
(call-next-method)))
(defmethod queue-get ((queue locking-queue) &optional default)
#-aclpc (declare (ignore default))
(with-queue-locked queue
(call-next-method)))
(defmethod queue-push ((queue locking-queue) item)
#-aclpc (declare (ignore item))
(with-queue-locked queue
(call-next-method)))
(defmethod queue-pop ((queue locking-queue) &optional default)
#-aclpc (declare (ignore default))
(with-queue-locked queue
(call-next-method)))