-
-
Notifications
You must be signed in to change notification settings - Fork 13
/
container.lisp
232 lines (192 loc) · 9.03 KB
/
container.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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
(in-package #:org.shirakumo.alloy)
(defclass element ()
())
(defclass container (sequences:sequence)
())
(defgeneric enter (element container &key &allow-other-keys))
(defgeneric leave (element container))
(defgeneric update (element container &key &allow-other-keys))
(defgeneric element-count (container))
(defgeneric elements (container))
(defgeneric element-index (element container))
(defgeneric index-element (index container))
(defgeneric call-with-elements (function container &key start end from-end))
(defgeneric clear (container))
(defmethod sequences:length ((container container))
(element-count container))
(defmethod sequences:elt ((container container) index)
(index-element index container))
(defmacro do-elements ((element container &key start end result from-end) &body body)
(let ((thunk (gensym "THUNK")))
`(block NIL
(flet ((,thunk (,element)
,@body))
(call-with-elements #',thunk ,container :start ,start :end ,end :from-end ,from-end)
,result))))
(defmethod shared-initialize :around ((container container) slots &key (elements NIL c-p))
(call-next-method)
(when c-p
(clear container)
(map NIL (lambda (e) (enter e container)) elements)))
(defmethod describe-object :after ((container container) stream)
(format stream "~&~%Container Tree:~%")
(let ((*level* 0))
(declare (special *level*))
(labels ((traverse (thing)
(format stream "~v{ ~}~a~%" (* *level* 2) '(0) thing)
(when (typep thing 'container)
(let ((*level* (1+ *level*)))
(declare (special *level*))
(do-elements (element thing)
(traverse element))))))
(traverse container))))
(defmethod element-count ((container container))
(length (elements container)))
(defmethod elements ((container container))
(let ((list ()))
(do-elements (element container :result (nreverse list))
(push element list))))
(defmethod clear ((container container))
(do-elements (element container)
(leave element container)))
(defclass vector-container (container)
((elements :initform (make-array 0 :adjustable T :fill-pointer T :initial-element NIL) :reader elements)))
(defmethod enter ((element element) (container vector-container) &key index)
(if index
(array-utils:vector-push-extend-position element (elements container) index)
(vector-push-extend element (elements container)))
element)
(defmethod leave ((element element) (container vector-container))
(array-utils:vector-pop-position (elements container) (position element (elements container)))
element)
(defmethod update ((element element) (container vector-container) &key index)
(when index
(let ((pos (position element (elements container))))
(array-utils:vector-pop-position (elements container) pos)
(array-utils:vector-push-extend-position element (elements container) index)))
element)
(defmethod call-with-elements (function (container vector-container) &key start end from-end)
(let* ((elements (elements container))
(start (or start 0))
(end (or end (length elements)))
(length (length elements)))
(if from-end
(loop for i downfrom (1- end)
while (<= start i)
do (funcall function (aref elements i))
(when (< (length elements) length)
;; Decrease to make sure we don't skip or run over.
(setf length (length elements))
(decf end)
(setf i (min end (1+ i)))))
(loop for i from start
while (< i end)
do (funcall function (aref elements i))
(when (< (length elements) length)
;; Decrease to make sure we don't skip or run over.
(setf length (length elements))
(decf end)
(decf i))))))
(defmethod element-index ((element element) (container vector-container))
(position element (elements container)))
(defmethod index-element ((index integer) (container vector-container))
(aref (elements container) index))
(defmethod clear ((container vector-container))
(loop for i downfrom (1- (length (elements container))) to 0
do (leave (aref (elements container) i) container)))
(defclass stack-container (container)
((layers :initform (make-array 0 :adjustable T :fill-pointer T) :reader layers)))
(defmethod enter ((element element) (container stack-container) &key (layer (max 0 (1- (length (layers container))))))
(let ((layers (layers container)))
(when (<= (length layers) layer)
(adjust-array layers (1+ layer) :initial-element NIL :fill-pointer (1+ layer))
(loop for i from 0 to layer
do (unless (aref layers i)
(setf (aref layers i) (make-array 0 :adjustable T :fill-pointer T)))))
(vector-push-extend element (aref layers layer))))
(defmethod update ((element element) (container stack-container) &key layer)
(when layer
(let ((layers (layers container)))
(loop for layer across layers
for position = (position element layer)
do (when position
(array-utils:vector-pop-position layer position)
(return)))
(when (<= (length layers) layer)
(adjust-array layers (1+ layer) :initial-element NIL :fill-pointer (1+ layer))
(loop for i from 0 to layer
do (unless (aref layers i)
(setf (aref layers i) (make-array 0 :adjustable T :fill-pointer T)))))
(vector-push-extend element (aref layers layer)))))
(defmethod leave ((element element) (container stack-container))
(loop for layer across (layers container)
for position = (position element layer)
do (when position
(array-utils:vector-pop-position layer position)
(return))))
(defmethod element-count ((container stack-container))
(loop for layer across (layers container)
sum (length layer)))
(defmethod elements ((container stack-container))
(let ((list ()))
(loop for layer across (layers container)
do (loop for element across layer
do (push element list)))
(nreverse list)))
(defmethod element-index ((element element) (container stack-container))
(loop for layer across (layers container)
for row from 0
for col = (position element layer)
do (when col (return (cons row col)))))
(defmethod index-element ((index cons) (container stack-container))
(unless (<= 0 (car index) (1- (length (layers container))))
(error 'index-out-of-range :index (car index) :range (list 0 (1- (length (layers container))))))
(let ((layer (aref (layers container) (car index))))
(unless (<= 0 (cdr index) (1- (length layer)))
(error 'index-out-of-range :index (cdr index) :range (list 0 (1- (length layer)))))
(aref layer (cdr index))))
(defmethod call-with-elements (function (container stack-container) &key start end from-end)
(let ((start (or start 0)))
(if from-end
(error "FIXME: implement.")
(loop with i = 0
for layer across (layers container)
while (or (not end) (<= end i))
do (loop for element across layer
while (or (not end) (<= end i))
do (when (<= start i)
(funcall function element))
(incf i))))))
(defmethod clear ((container stack-container))
(loop for layer across (layers container)
do (loop for i downfrom (1- (length layer)) to 0
do (leave (aref layer i) container))))
(defclass single-container (container)
((inner :initarg :inner :initform NIL :accessor inner)))
(defmethod enter ((element element) (container single-container) &key)
(when (inner container)
(cerror "Replace the element" 'place-already-occupied
:bad-element element :place T :layout container :existing (inner container)))
(setf (inner container) element))
(defmethod update ((element element) (container single-container) &key))
(defmethod leave ((element element) (container single-container))
(setf (inner container) NIL))
(defmethod call-with-elements (function (container single-container) &key start end from-end)
(declare (ignore start end from-end))
(when (inner container)
(funcall function (inner container))))
(defmethod element-count ((container single-container))
(if (inner container) 1 0))
(defmethod elements ((container single-container))
(when (inner container) (list (inner container))))
(defmethod element-index ((element element) (container single-container))
(when (eq element (inner container)) 0))
(defmethod index-element ((index integer) (container single-container))
(if (and (inner container) (= 0 index))
(inner container)
(error 'index-out-of-range :index index :range (list 0 (if (inner container) 1 0)))))
(defmethod clear ((container single-container))
(setf (inner container) 0))
(defun enter-all (container &rest elements)
(dolist (element elements container)
(enter element container)))