Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(658)

Side by Side Diff: sdk/lib/collection/queue.dart

Issue 1001863002: Fix DoubleLinkedQueue so that appending to entries also update the queue length. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix type warnings. Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/corelib/queue_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | tests/corelib/queue_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698