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

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

Issue 138953015: Fix bug in DoubleLinkedQueue where removing from empty queue throws. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 11 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 | sdk/lib/core/annotations.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 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 94
95 /** 95 /**
96 * An entry in a doubly linked list. It contains a pointer to the next 96 * An entry in a doubly linked list. It contains a pointer to the next
97 * entry, the previous entry, and the boxed element. 97 * entry, the previous entry, and the boxed element.
98 */ 98 */
99 class DoubleLinkedQueueEntry<E> { 99 class DoubleLinkedQueueEntry<E> {
100 DoubleLinkedQueueEntry<E> _previous; 100 DoubleLinkedQueueEntry<E> _previous;
101 DoubleLinkedQueueEntry<E> _next; 101 DoubleLinkedQueueEntry<E> _next;
102 E _element; 102 E _element;
103 103
104 DoubleLinkedQueueEntry(E e) { 104 DoubleLinkedQueueEntry(E e) : _element = e;
105 _element = e;
106 }
107 105
108 void _link(DoubleLinkedQueueEntry<E> p, 106 void _link(DoubleLinkedQueueEntry<E> previous,
109 DoubleLinkedQueueEntry<E> n) { 107 DoubleLinkedQueueEntry<E> next) {
110 _next = n; 108 _next = next;
111 _previous = p; 109 _previous = previous;
112 p._next = this; 110 previous._next = this;
113 n._previous = this; 111 next._previous = this;
114 } 112 }
115 113
116 void append(E e) { 114 void append(E e) {
117 new DoubleLinkedQueueEntry<E>(e)._link(this, _next); 115 new DoubleLinkedQueueEntry<E>(e)._link(this, _next);
118 } 116 }
119 117
120 void prepend(E e) { 118 void prepend(E e) {
121 new DoubleLinkedQueueEntry<E>(e)._link(_previous, this); 119 new DoubleLinkedQueueEntry<E>(e)._link(_previous, this);
122 } 120 }
123 121
(...skipping 21 matching lines...) Expand all
145 return _element; 143 return _element;
146 } 144 }
147 145
148 void set element(E e) { 146 void set element(E e) {
149 _element = e; 147 _element = e;
150 } 148 }
151 } 149 }
152 150
153 /** 151 /**
154 * A sentinel in a double linked list is used to manipulate the list 152 * A sentinel in a double linked list is used to manipulate the list
155 * at both ends. A double linked list has exactly one sentinel, which 153 * at both ends.
156 * is the only entry when the list is constructed. Initially, a 154 * A double linked list has exactly one sentinel,
157 * sentinel has its next and previous entry point to itself. A 155 * which is the only entry when the list is constructed.
158 * sentinel does not box any user element. 156 * Initially, a sentinel has its next and previous entry point to itself.
157 * A sentinel does not box any user element.
159 */ 158 */
160 class _DoubleLinkedQueueEntrySentinel<E> extends DoubleLinkedQueueEntry<E> { 159 class _DoubleLinkedQueueEntrySentinel<E> extends DoubleLinkedQueueEntry<E> {
161 _DoubleLinkedQueueEntrySentinel() : super(null) { 160 _DoubleLinkedQueueEntrySentinel() : super(null) {
162 _link(this, this); 161 _link(this, this);
163 } 162 }
164 163
165 E remove() { 164 E remove() {
166 throw new StateError("Empty queue"); 165 throw new StateError("Empty queue");
167 } 166 }
168 167
169 DoubleLinkedQueueEntry<E> _asNonSentinelEntry() { 168 DoubleLinkedQueueEntry<E> _asNonSentinelEntry() {
170 return null; 169 return null;
171 } 170 }
172 171
173 void set element(E e) { 172 void set element(E e) {
174 // This setter is unreachable. 173 // This setter is unreachable.
174 // TODO(lrn): Don't inherit the field if we don't use it.
175 assert(false); 175 assert(false);
176 } 176 }
177 177
178 E get element { 178 E get element {
179 throw new StateError("Empty queue"); 179 throw new StateError("Empty queue");
180 } 180 }
181 } 181 }
182 182
183 /** 183 /**
184 * A [Queue] implementation based on a double-linked list. 184 * A [Queue] implementation based on a double-linked list.
185 * 185 *
186 * Allows constant time add, remove-at-ends and peek operations. 186 * Allows constant time add, remove-at-ends and peek operations.
187 *
188 * Can do [removeAll] and [retainAll] in linear time.
189 */ 187 */
190 class DoubleLinkedQueue<E> extends IterableBase<E> implements Queue<E> { 188 class DoubleLinkedQueue<E> extends IterableBase<E> implements Queue<E> {
191 _DoubleLinkedQueueEntrySentinel<E> _sentinel; 189 _DoubleLinkedQueueEntrySentinel<E> _sentinel;
192 int _elementCount = 0; 190 int _elementCount = 0;
193 191
194 DoubleLinkedQueue() { 192 DoubleLinkedQueue() {
195 _sentinel = new _DoubleLinkedQueueEntrySentinel<E>(); 193 _sentinel = new _DoubleLinkedQueueEntrySentinel<E>();
196 } 194 }
197 195
198 factory DoubleLinkedQueue.from(Iterable<E> other) { 196 factory DoubleLinkedQueue.from(Iterable<E> other) {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 return result; 231 return result;
234 } 232 }
235 233
236 E removeFirst() { 234 E removeFirst() {
237 E result = _sentinel._next.remove(); 235 E result = _sentinel._next.remove();
238 _elementCount--; 236 _elementCount--;
239 return result; 237 return result;
240 } 238 }
241 239
242 bool remove(Object o) { 240 bool remove(Object o) {
243 DoubleLinkedQueueEntry<E> entry = firstEntry(); 241 DoubleLinkedQueueEntry<E> entry = _sentinel._next;
244 while (!identical(entry, _sentinel)) { 242 while (!identical(entry, _sentinel)) {
245 if (entry.element == o) { 243 if (entry.element == o) {
246 entry.remove(); 244 entry.remove();
247 _elementCount--; 245 _elementCount--;
248 return true; 246 return true;
249 } 247 }
250 entry = entry._next; 248 entry = entry._next;
251 } 249 }
252 return false; 250 return false;
253 } 251 }
254 252
255 void _filter(bool test(E element), bool removeMatching) { 253 void _filter(bool test(E element), bool removeMatching) {
256 DoubleLinkedQueueEntry<E> entry = firstEntry(); 254 DoubleLinkedQueueEntry<E> entry = _sentinel._next;
257 while (!identical(entry, _sentinel)) { 255 while (!identical(entry, _sentinel)) {
258 DoubleLinkedQueueEntry<E> next = entry._next; 256 DoubleLinkedQueueEntry<E> next = entry._next;
259 if (identical(removeMatching, test(entry.element))) { 257 if (identical(removeMatching, test(entry.element))) {
260 entry.remove(); 258 entry.remove();
261 _elementCount--; 259 _elementCount--;
262 } 260 }
263 entry = next; 261 entry = next;
264 } 262 }
265 } 263 }
266 264
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 } 345 }
348 346
349 /** 347 /**
350 * List based [Queue]. 348 * List based [Queue].
351 * 349 *
352 * Keeps a cyclic buffer of elements, and grows to a larger buffer when 350 * Keeps a cyclic buffer of elements, and grows to a larger buffer when
353 * it fills up. This guarantees constant time peek and remove operations, and 351 * it fills up. This guarantees constant time peek and remove operations, and
354 * amortized constant time add operations. 352 * amortized constant time add operations.
355 * 353 *
356 * The structure is efficient for any queue or stack usage. 354 * The structure is efficient for any queue or stack usage.
357 *
358 * Operations like [removeAll] and [removeWhere] are very
359 * inefficient. If those are needed, use a [DoubleLinkedQueue] instead.
360 */ 355 */
361 class ListQueue<E> extends IterableBase<E> implements Queue<E> { 356 class ListQueue<E> extends IterableBase<E> implements Queue<E> {
362 static const int _INITIAL_CAPACITY = 8; 357 static const int _INITIAL_CAPACITY = 8;
363 List<E> _table; 358 List<E> _table;
364 int _head; 359 int _head;
365 int _tail; 360 int _tail;
366 int _modificationCount = 0; 361 int _modificationCount = 0;
367 362
368 /** 363 /**
369 * Create an empty queue. 364 * Create an empty queue.
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after
712 _queue._checkModification(_modificationCount); 707 _queue._checkModification(_modificationCount);
713 if (_position == _end) { 708 if (_position == _end) {
714 _current = null; 709 _current = null;
715 return false; 710 return false;
716 } 711 }
717 _current = _queue._table[_position]; 712 _current = _queue._table[_position];
718 _position = (_position + 1) & (_queue._table.length - 1); 713 _position = (_position + 1) & (_queue._table.length - 1);
719 return true; 714 return true;
720 } 715 }
721 } 716 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/core/annotations.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698