Chromium Code Reviews| Index: sdk/lib/collection/queue.dart |
| diff --git a/sdk/lib/collection/queue.dart b/sdk/lib/collection/queue.dart |
| index 2e6a24afa2ec7848c0a22513dbb6553aaff53f1f..69b18d233053ddac4fded0edc5dc519447382fa6 100644 |
| --- a/sdk/lib/collection/queue.dart |
| +++ b/sdk/lib/collection/queue.dart |
| @@ -322,7 +322,12 @@ class DoubleLinkedQueue<E> extends Iterable<E> implements Queue<E> { |
| bool remove(Object o) { |
| _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink; |
| while (!identical(entry, _sentinel)) { |
| - if (entry._element == o) { |
| + bool equals = (entry._element == o); |
| + if (!identical(this, entry._queue)) { |
| + // Entry must still be in the queue. |
| + throw new ConcurrentModificationError(this); |
| + } |
| + if (equals) { |
| entry._remove(); |
| _elementCount--; |
| return true; |
| @@ -335,8 +340,13 @@ class DoubleLinkedQueue<E> extends Iterable<E> implements Queue<E> { |
| void _filter(bool test(E element), bool removeMatching) { |
| _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink; |
| while (!identical(entry, _sentinel)) { |
| - _DoubleLinkedQueueEntry<E> next = entry._nextLink; |
| - if (identical(removeMatching, test(entry._element))) { |
| + bool matches = test(entry._element); |
| + if (!identical(this, entry._queue)) { |
| + // Entry must still be in the queue. |
| + throw new ConcurrentModificationError(this); |
| + } |
| + _DoubleLinkedQueueEntry<E> next = entry._nextLink; // Cannot be null. |
| + if (identical(removeMatching, matches)) { |
| entry._remove(); |
| _elementCount--; |
| } |
| @@ -364,7 +374,7 @@ class DoubleLinkedQueue<E> extends Iterable<E> implements Queue<E> { |
| E get single { |
| // Note that this throws correctly if the queue is empty |
| - // because reading element on the sentinel throws. |
| + // because reading the element of the sentinel throws. |
| if (identical(_sentinel._nextLink, _sentinel._previousLink)) { |
| _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink; |
| return entry._element; |
| @@ -372,14 +382,34 @@ class DoubleLinkedQueue<E> extends Iterable<E> implements Queue<E> { |
| throw IterableElementError.tooMany(); |
| } |
| - DoubleLinkedQueueEntry<E> lastEntry() { |
| - return _sentinel.previousEntry(); |
| - } |
| - |
| + /** |
| + * The entry object of the first element in the queue. |
| + * |
| + * Each element of the queue has an associated [DoubleLinkedQueueEntry]. |
| + * Returns the entry object corresponding to the first element of the queue. |
| + * |
| + * The entry objects can also be accessed using [lastEntry], |
| + * and they can be iterated using [DoubleLinkedQueueEntry.nextEntry()] and |
| + * [DoubleLinkedQueueEntry.previousEntry()]. |
| + */ |
| DoubleLinkedQueueEntry<E> firstEntry() { |
| return _sentinel.nextEntry(); |
| } |
| + /** |
| + * The entry object of the last element in the queue. |
| + * |
| + * Each element of the queue has an associated [DoubleLinkedQueueEntry]. |
| + * Returns the entry object corresponding to the last element of the queue. |
| + * |
| + * The entry objects can also be accessed using [firstEntry], |
| + * and they can be iterated using [DoubleLinkedQueueEntry.nextEntry()] and |
| + * [DoubleLinkedQueueEntry.previousEntry()]. |
| + */ |
| + DoubleLinkedQueueEntry<E> lastEntry() { |
|
floitsch
2016/12/01 18:31:09
not a getter?
argh :(
|
| + return _sentinel.previousEntry(); |
| + } |
| + |
| bool get isEmpty { |
| return (identical(_sentinel._nextLink, _sentinel)); |
| } |
| @@ -390,13 +420,40 @@ class DoubleLinkedQueue<E> extends Iterable<E> implements Queue<E> { |
| _elementCount = 0; |
| } |
| - void forEachEntry(void f(DoubleLinkedQueueEntry<E> element)) { |
| + /** |
| + * Calls [action] for each entry object of this double-linked queue. |
| + * |
| + * Each element of the queue has an associated [DoubleLinkedQueueEntry]. |
| + * This method iterates the entry objects from first to last and calls |
| + * [action] with each object in turn. |
| + * |
| + * The entry objects can also be accessed using [firstEntry] and [lastEntry], |
| + * and iterated using [DoubleLinkedQueueEntry.nextEntry()] and |
| + * [DoubleLinkedQueueEntry.previousEntry()]. |
| + * |
| + * The [action] function can use methods on [DoubleLinkedQueueEntry] to remove |
| + * the entry or it can insert elements before or after then entry. |
| + * If the current entry is removed, iteration continues with the entry that |
| + * was following the current entry when [action] was called. Any elements |
| + * inserted after the current element before it is removed will not be |
| + * visited by the iteration. |
| + */ |
| + void forEachEntry(void action(DoubleLinkedQueueEntry<E> element)) { |
| _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink; |
| while (!identical(entry, _sentinel)) { |
| - _DoubleLinkedQueueEntry<E> nextEntry = entry._nextLink; |
| _DoubleLinkedQueueElement<E> element = entry; |
| - f(element); |
| - entry = nextEntry; |
| + _DoubleLinkedQueueEntry<E> next = element._nextLink; |
| + // Remember both entry and entry._nextLink. |
| + // If someone calls `element.remove()` we continue from `next`. |
| + // Otherwise we use the value of entry._nextLink which may have been |
| + // updated. |
| + action(element); |
| + if (identical(this, entry._queue)) { |
| + next = entry._nextLink; |
| + } else if (!identical(this, next._queue)) { |
| + throw new ConcurrentModificationError(this); |
| + } |
| + entry = next; |
| } |
| } |
| @@ -424,7 +481,7 @@ class _DoubleLinkedQueueIterator<E> implements Iterator<E> { |
| return false; |
| } |
| _DoubleLinkedQueueElement<E> elementEntry = _nextEntry; |
| - if (elementEntry._queue == null) { |
| + if (!identical(_sentinel._queue, elementEntry._queue)) { |
| throw new ConcurrentModificationError(_sentinel._queue); |
| } |
| _current = elementEntry._element; |
| @@ -714,7 +771,7 @@ class ListQueue<E> extends ListIterable<E> implements Queue<E> { |
| /** |
| * Removes the element at [offset] into [_table]. |
| * |
| - * Removal is performed by linerarly moving elements either before or after |
| + * Removal is performed by linearly moving elements either before or after |
| * [offset] by one position. |
| * |
| * Returns the new offset of the following element. This may be the same |