OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart.collection; | 5 part of dart.collection; |
6 | 6 |
7 /** | 7 /** |
8 * A [Queue] is a collection that can be manipulated at both ends. One | 8 * A [Queue] is a collection that can be manipulated at both ends. One |
9 * can iterate over the elements of a queue through [forEach] or with | 9 * can iterate over the elements of a queue through [forEach] or with |
10 * an [Iterator]. | 10 * an [Iterator]. |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 */ | 89 */ |
90 void retainWhere(bool test(E element)); | 90 void retainWhere(bool test(E element)); |
91 | 91 |
92 /** | 92 /** |
93 * Removes all elements in the queue. The size of the queue becomes zero. | 93 * Removes all elements in the queue. The size of the queue becomes zero. |
94 */ | 94 */ |
95 void clear(); | 95 void clear(); |
96 } | 96 } |
97 | 97 |
98 | 98 |
| 99 class _DoubleLink { |
| 100 _DoubleLink _previous; |
| 101 _DoubleLink _next; |
| 102 |
| 103 void _link(_DoubleLink previous, |
| 104 _DoubleLink next) { |
| 105 _next = next; |
| 106 _previous = previous; |
| 107 if (previous != null) previous._next = this; |
| 108 if (next != null) next._previous = this; |
| 109 } |
| 110 |
| 111 void _unlink() { |
| 112 if (_previous != null) _previous._next = _next; |
| 113 if (_next != null) _next._previous = _previous; |
| 114 _next = null; |
| 115 _previous = null; |
| 116 } |
| 117 } |
| 118 |
99 /** | 119 /** |
100 * An entry in a doubly linked list. It contains a pointer to the next | 120 * An entry in a doubly linked list. It contains a pointer to the next |
101 * entry, the previous entry, and the boxed element. | 121 * entry, the previous entry, and the boxed element. |
102 */ | 122 */ |
103 class DoubleLinkedQueueEntry<E> { | 123 class DoubleLinkedQueueEntry<E> extends _DoubleLink { |
104 DoubleLinkedQueueEntry<E> _previous; | 124 E element; |
105 DoubleLinkedQueueEntry<E> _next; | |
106 E _element; | |
107 | 125 |
108 DoubleLinkedQueueEntry(E e) : _element = e; | 126 DoubleLinkedQueueEntry(this.element); |
109 | |
110 void _link(DoubleLinkedQueueEntry<E> previous, | |
111 DoubleLinkedQueueEntry<E> next) { | |
112 _next = next; | |
113 _previous = previous; | |
114 previous._next = this; | |
115 next._previous = this; | |
116 } | |
117 | 127 |
118 void append(E e) { | 128 void append(E e) { |
119 new DoubleLinkedQueueEntry<E>(e)._link(this, _next); | 129 new DoubleLinkedQueueEntry<E>(e)._link(this, _next); |
120 } | 130 } |
121 | 131 |
122 void prepend(E e) { | 132 void prepend(E e) { |
123 new DoubleLinkedQueueEntry<E>(e)._link(_previous, this); | 133 new DoubleLinkedQueueEntry<E>(e)._link(_previous, this); |
124 } | 134 } |
125 | 135 |
126 E remove() { | 136 E remove() { |
127 _previous._next = _next; | 137 _unlink(); |
128 _next._previous = _previous; | 138 return element; |
129 _next = null; | |
130 _previous = null; | |
131 return _element; | |
132 } | |
133 | |
134 DoubleLinkedQueueEntry<E> _asNonSentinelEntry() { | |
135 return this; | |
136 } | 139 } |
137 | 140 |
138 DoubleLinkedQueueEntry<E> previousEntry() { | 141 DoubleLinkedQueueEntry<E> previousEntry() { |
139 return _previous._asNonSentinelEntry(); | 142 return _previous; |
140 } | 143 } |
141 | 144 |
142 DoubleLinkedQueueEntry<E> nextEntry() { | 145 DoubleLinkedQueueEntry<E> nextEntry() { |
143 return _next._asNonSentinelEntry(); | 146 return _next; |
144 } | |
145 | |
146 E get element { | |
147 return _element; | |
148 } | |
149 | |
150 void set element(E e) { | |
151 _element = e; | |
152 } | 147 } |
153 } | 148 } |
154 | 149 |
| 150 /** |
| 151 * Interface for the link classes used by [DoubleLinkedQueue]. |
| 152 * |
| 153 * Both the [_DoubleLinkedQueueElement] and [_DoubleLinkedQueueSentinel] |
| 154 * implements this interface. |
| 155 * The entry contains a link back to the queue, so calling `append` |
| 156 * or `prepend` can correctly update the element count. |
| 157 */ |
| 158 abstract class _DoubleLinkedQueueEntry<E> extends _DoubleLink { |
| 159 DoubleLinkedQueue<E> _queue; |
| 160 _DoubleLinkedQueueEntry(this._queue); |
| 161 |
| 162 _DoubleLinkedQueueElement _asNonSentinelEntry(); |
| 163 |
| 164 void _append(E e) { |
| 165 new _DoubleLinkedQueueElement<E>(e, _queue)._link(this, _next); |
| 166 } |
| 167 |
| 168 void _prepend(E e) { |
| 169 new _DoubleLinkedQueueElement<E>(e, _queue)._link(_previous, this); |
| 170 } |
| 171 |
| 172 E _remove(); |
| 173 |
| 174 E get element; |
| 175 |
| 176 DoubleLinkedQueueEntry<E> nextEntry() { |
| 177 _DoubleLinkedQueueEntry next = _next; |
| 178 return next._asNonSentinelEntry(); |
| 179 } |
| 180 |
| 181 DoubleLinkedQueueEntry<E> previousEntry() { |
| 182 _DoubleLinkedQueueEntry previous = _previous; |
| 183 return previous._asNonSentinelEntry(); |
| 184 } |
| 185 } |
| 186 |
| 187 /** |
| 188 * The actual entry type used by the [DoubleLinkedQueue]. |
| 189 * |
| 190 * The entry contains a reference to the queue, allowing |
| 191 * [append]/[prepend] to update the list length. |
| 192 */ |
| 193 class _DoubleLinkedQueueElement<E> extends _DoubleLinkedQueueEntry<E> |
| 194 implements DoubleLinkedQueueEntry<E> { |
| 195 E element; |
| 196 _DoubleLinkedQueueElement(this.element, DoubleLinkedQueue<E> queue) |
| 197 : super(queue); |
| 198 |
| 199 void append(E e) { |
| 200 _append(e); |
| 201 if (_queue != null) _queue._elementCount++; |
| 202 } |
| 203 |
| 204 void prepend(E e) { |
| 205 _prepend(e); |
| 206 if (_queue != null) _queue._elementCount++; |
| 207 } |
| 208 |
| 209 E _remove() { |
| 210 _queue = null; |
| 211 _unlink(); |
| 212 return element; |
| 213 } |
| 214 |
| 215 E remove() { |
| 216 if (_queue != null) _queue._elementCount--; |
| 217 return _remove(); |
| 218 } |
| 219 |
| 220 _DoubleLinkedQueueElement _asNonSentinelEntry() { |
| 221 return this; |
| 222 } |
| 223 } |
| 224 |
155 /** | 225 /** |
156 * A sentinel in a double linked list is used to manipulate the list | 226 * A sentinel in a double linked list is used to manipulate the list |
157 * at both ends. | 227 * at both ends. |
158 * A double linked list has exactly one sentinel, | 228 * A double linked list has exactly one sentinel, |
159 * which is the only entry when the list is constructed. | 229 * which is the only entry when the list is constructed. |
160 * Initially, a sentinel has its next and previous entry point to itself. | 230 * Initially, a sentinel has its next and previous entry point to itself. |
161 * A sentinel does not box any user element. | 231 * A sentinel does not box any user element. |
162 */ | 232 */ |
163 class _DoubleLinkedQueueEntrySentinel<E> extends DoubleLinkedQueueEntry<E> { | 233 class _DoubleLinkedQueueSentinel<E> extends _DoubleLinkedQueueEntry<E> { |
164 _DoubleLinkedQueueEntrySentinel() : super(null) { | 234 _DoubleLinkedQueueSentinel(DoubleLinkedQueue queue) : super(queue) { |
165 _link(this, this); | 235 _previous = this; |
| 236 _next = this; |
166 } | 237 } |
167 | 238 |
168 E remove() { | 239 _DoubleLinkedQueueElement _asNonSentinelEntry() { |
| 240 return null; |
| 241 } |
| 242 |
| 243 /** Hit by, e.g., [DoubleLinkedQueue.removeFirst] if the queue is empty. */ |
| 244 E _remove() { |
169 throw IterableElementError.noElement(); | 245 throw IterableElementError.noElement(); |
170 } | 246 } |
171 | 247 |
172 DoubleLinkedQueueEntry<E> _asNonSentinelEntry() { | 248 /** Hit by, e.g., [DoubleLinkedQueue.first] if the queue is empty. */ |
173 return null; | |
174 } | |
175 | |
176 void set element(E e) { | |
177 // This setter is unreachable. | |
178 // TODO(lrn): Don't inherit the field if we don't use it. | |
179 assert(false); | |
180 } | |
181 | |
182 E get element { | 249 E get element { |
183 throw IterableElementError.noElement(); | 250 throw IterableElementError.noElement(); |
184 } | 251 } |
185 } | 252 } |
186 | 253 |
187 /** | 254 /** |
188 * A [Queue] implementation based on a double-linked list. | 255 * A [Queue] implementation based on a double-linked list. |
189 * | 256 * |
190 * Allows constant time add, remove-at-ends and peek operations. | 257 * Allows constant time add, remove-at-ends and peek operations. |
191 */ | 258 */ |
192 class DoubleLinkedQueue<E> extends IterableBase<E> implements Queue<E> { | 259 class DoubleLinkedQueue<E> extends IterableBase<E> implements Queue<E> { |
193 _DoubleLinkedQueueEntrySentinel<E> _sentinel; | 260 _DoubleLinkedQueueSentinel<E> _sentinel; |
194 int _elementCount = 0; | 261 int _elementCount = 0; |
195 | 262 |
196 DoubleLinkedQueue() { | 263 DoubleLinkedQueue() { |
197 _sentinel = new _DoubleLinkedQueueEntrySentinel<E>(); | 264 _sentinel = new _DoubleLinkedQueueSentinel<E>(this); |
198 } | 265 } |
199 | 266 |
200 /** | 267 /** |
201 * Creates a double-linked queue containing all [elements]. | 268 * Creates a double-linked queue containing all [elements]. |
202 * | 269 * |
203 * The element order in the queue is as if the elements were added using | 270 * The element order in the queue is as if the elements were added using |
204 * [addLast] in the order provided by [elements.iterator]. | 271 * [addLast] in the order provided by [elements.iterator]. |
205 */ | 272 */ |
206 factory DoubleLinkedQueue.from(Iterable elements) { | 273 factory DoubleLinkedQueue.from(Iterable elements) { |
207 Queue<E> list = new DoubleLinkedQueue(); | 274 Queue<E> list = new DoubleLinkedQueue<E>(); |
208 for (final E e in elements) { | 275 for (final E e in elements) { |
209 list.addLast(e); | 276 list.addLast(e); |
210 } | 277 } |
211 return list; | 278 return list; |
212 } | 279 } |
213 | 280 |
214 int get length => _elementCount; | 281 int get length => _elementCount; |
215 | 282 |
216 void addLast(E value) { | 283 void addLast(E value) { |
217 _sentinel.prepend(value); | 284 _sentinel._prepend(value); |
218 _elementCount++; | 285 _elementCount++; |
219 } | 286 } |
220 | 287 |
221 void addFirst(E value) { | 288 void addFirst(E value) { |
222 _sentinel.append(value); | 289 _sentinel._append(value); |
223 _elementCount++; | 290 _elementCount++; |
224 } | 291 } |
225 | 292 |
226 void add(E value) { | 293 void add(E value) { |
227 _sentinel.prepend(value); | 294 _sentinel._prepend(value); |
228 _elementCount++; | 295 _elementCount++; |
229 } | 296 } |
230 | 297 |
231 void addAll(Iterable<E> iterable) { | 298 void addAll(Iterable<E> iterable) { |
232 for (final E value in iterable) { | 299 for (final E value in iterable) { |
233 _sentinel.prepend(value); | 300 _sentinel._prepend(value); |
234 _elementCount++; | 301 _elementCount++; |
235 } | 302 } |
236 } | 303 } |
237 | 304 |
238 E removeLast() { | 305 E removeLast() { |
239 E result = _sentinel._previous.remove(); | 306 _DoubleLinkedQueueEntry lastEntry = _sentinel._previous; |
| 307 E result = lastEntry._remove(); |
240 _elementCount--; | 308 _elementCount--; |
241 return result; | 309 return result; |
242 } | 310 } |
243 | 311 |
244 E removeFirst() { | 312 E removeFirst() { |
245 E result = _sentinel._next.remove(); | 313 _DoubleLinkedQueueEntry firstEntry = _sentinel._next; |
| 314 E result = firstEntry._remove(); |
246 _elementCount--; | 315 _elementCount--; |
247 return result; | 316 return result; |
248 } | 317 } |
249 | 318 |
250 bool remove(Object o) { | 319 bool remove(Object o) { |
251 DoubleLinkedQueueEntry<E> entry = _sentinel._next; | 320 _DoubleLinkedQueueEntry<E> entry = _sentinel._next; |
252 while (!identical(entry, _sentinel)) { | 321 while (!identical(entry, _sentinel)) { |
253 if (entry.element == o) { | 322 if (entry.element == o) { |
254 entry.remove(); | 323 entry._remove(); |
255 _elementCount--; | 324 _elementCount--; |
256 return true; | 325 return true; |
257 } | 326 } |
258 entry = entry._next; | 327 entry = entry._next; |
259 } | 328 } |
260 return false; | 329 return false; |
261 } | 330 } |
262 | 331 |
263 void _filter(bool test(E element), bool removeMatching) { | 332 void _filter(bool test(E element), bool removeMatching) { |
264 DoubleLinkedQueueEntry<E> entry = _sentinel._next; | 333 _DoubleLinkedQueueEntry<E> entry = _sentinel._next; |
265 while (!identical(entry, _sentinel)) { | 334 while (!identical(entry, _sentinel)) { |
266 DoubleLinkedQueueEntry<E> next = entry._next; | 335 _DoubleLinkedQueueEntry<E> next = entry._next; |
267 if (identical(removeMatching, test(entry.element))) { | 336 if (identical(removeMatching, test(entry.element))) { |
268 entry.remove(); | 337 entry._remove(); |
269 _elementCount--; | 338 _elementCount--; |
270 } | 339 } |
271 entry = next; | 340 entry = next; |
272 } | 341 } |
273 } | 342 } |
274 | 343 |
275 void removeWhere(bool test(E element)) { | 344 void removeWhere(bool test(E element)) { |
276 _filter(test, true); | 345 _filter(test, true); |
277 } | 346 } |
278 | 347 |
279 void retainWhere(bool test(E element)) { | 348 void retainWhere(bool test(E element)) { |
280 _filter(test, false); | 349 _filter(test, false); |
281 } | 350 } |
282 | 351 |
283 E get first { | 352 E get first { |
284 return _sentinel._next.element; | 353 _DoubleLinkedQueueEntry firstEntry = _sentinel._next; |
| 354 return firstEntry.element; |
285 } | 355 } |
286 | 356 |
287 E get last { | 357 E get last { |
288 return _sentinel._previous.element; | 358 _DoubleLinkedQueueEntry lastEntry = _sentinel._previous; |
| 359 return lastEntry.element; |
289 } | 360 } |
290 | 361 |
291 E get single { | 362 E get single { |
292 // Note that this throws correctly if the queue is empty. | 363 // Note that this throws correctly if the queue is empty |
| 364 // because reading element on the sentinel throws. |
293 if (identical(_sentinel._next, _sentinel._previous)) { | 365 if (identical(_sentinel._next, _sentinel._previous)) { |
294 return _sentinel._next.element; | 366 _DoubleLinkedQueueEntry entry = _sentinel._next; |
| 367 return entry.element; |
295 } | 368 } |
296 throw IterableElementError.tooMany(); | 369 throw IterableElementError.tooMany(); |
297 } | 370 } |
298 | 371 |
299 DoubleLinkedQueueEntry<E> lastEntry() { | 372 DoubleLinkedQueueEntry<E> lastEntry() { |
300 return _sentinel.previousEntry(); | 373 return _sentinel.previousEntry(); |
301 } | 374 } |
302 | 375 |
303 DoubleLinkedQueueEntry<E> firstEntry() { | 376 DoubleLinkedQueueEntry<E> firstEntry() { |
304 return _sentinel.nextEntry(); | 377 return _sentinel.nextEntry(); |
(...skipping 19 matching lines...) Expand all Loading... |
324 } | 397 } |
325 | 398 |
326 _DoubleLinkedQueueIterator<E> get iterator { | 399 _DoubleLinkedQueueIterator<E> get iterator { |
327 return new _DoubleLinkedQueueIterator<E>(_sentinel); | 400 return new _DoubleLinkedQueueIterator<E>(_sentinel); |
328 } | 401 } |
329 | 402 |
330 String toString() => IterableBase.iterableToFullString(this, '{', '}'); | 403 String toString() => IterableBase.iterableToFullString(this, '{', '}'); |
331 } | 404 } |
332 | 405 |
333 class _DoubleLinkedQueueIterator<E> implements Iterator<E> { | 406 class _DoubleLinkedQueueIterator<E> implements Iterator<E> { |
334 _DoubleLinkedQueueEntrySentinel<E> _sentinel; | 407 _DoubleLinkedQueueSentinel<E> _sentinel; |
335 DoubleLinkedQueueEntry<E> _nextEntry = null; | 408 _DoubleLinkedQueueEntry<E> _nextEntry = null; |
336 E _current; | 409 E _current; |
337 | 410 |
338 _DoubleLinkedQueueIterator(_DoubleLinkedQueueEntrySentinel<E> sentinel) | 411 _DoubleLinkedQueueIterator(_DoubleLinkedQueueSentinel<E> sentinel) |
339 : _sentinel = sentinel, _nextEntry = sentinel._next; | 412 : _sentinel = sentinel, _nextEntry = sentinel._next; |
340 | 413 |
341 bool moveNext() { | 414 bool moveNext() { |
342 // When [_currentEntry] it is set to [:null:] then it is at the end. | 415 if (identical(_nextEntry, _sentinel)) { |
343 if (!identical(_nextEntry, _sentinel)) { | 416 _current = null; |
344 _current = _nextEntry._element; | 417 _nextEntry = null; |
345 _nextEntry = _nextEntry._next; | 418 _sentinel = null; |
346 return true; | 419 return false; |
347 } | 420 } |
348 _current = null; | 421 _DoubleLinkedQueueElement elementEntry = _nextEntry; |
349 _nextEntry = _sentinel = null; // Still identical. | 422 if (elementEntry._queue == null) { |
350 return false; | 423 throw new ConcurrentModificationError(_sentinel._queue); |
| 424 } |
| 425 _current = elementEntry.element; |
| 426 _nextEntry = elementEntry._next; |
| 427 return true; |
351 } | 428 } |
352 | 429 |
353 E get current => _current; | 430 E get current => _current; |
354 } | 431 } |
355 | 432 |
356 /** | 433 /** |
357 * List based [Queue]. | 434 * List based [Queue]. |
358 * | 435 * |
359 * Keeps a cyclic buffer of elements, and grows to a larger buffer when | 436 * Keeps a cyclic buffer of elements, and grows to a larger buffer when |
360 * it fills up. This guarantees constant time peek and remove operations, and | 437 * it fills up. This guarantees constant time peek and remove operations, and |
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
733 _queue._checkModification(_modificationCount); | 810 _queue._checkModification(_modificationCount); |
734 if (_position == _end) { | 811 if (_position == _end) { |
735 _current = null; | 812 _current = null; |
736 return false; | 813 return false; |
737 } | 814 } |
738 _current = _queue._table[_position]; | 815 _current = _queue._table[_position]; |
739 _position = (_position + 1) & (_queue._table.length - 1); | 816 _position = (_position + 1) & (_queue._table.length - 1); |
740 return true; | 817 return true; |
741 } | 818 } |
742 } | 819 } |
OLD | NEW |