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

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

Issue 2540993002: Fix DoubleLinkedListQueue misbehavior on concurrent modification. (Closed)
Patch Set: Created 4 years 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
« no previous file with comments | « no previous file | sdk/lib/core/num.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 304 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 E removeFirst() { 315 E removeFirst() {
316 _DoubleLinkedQueueEntry<E> firstEntry = _sentinel._nextLink; 316 _DoubleLinkedQueueEntry<E> firstEntry = _sentinel._nextLink;
317 E result = firstEntry._remove(); 317 E result = firstEntry._remove();
318 _elementCount--; 318 _elementCount--;
319 return result; 319 return result;
320 } 320 }
321 321
322 bool remove(Object o) { 322 bool remove(Object o) {
323 _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink; 323 _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
324 while (!identical(entry, _sentinel)) { 324 while (!identical(entry, _sentinel)) {
325 if (entry._element == o) { 325 bool equals = (entry._element == o);
326 if (!identical(this, entry._queue)) {
327 // Entry must still be in the queue.
328 throw new ConcurrentModificationError(this);
329 }
330 if (equals) {
326 entry._remove(); 331 entry._remove();
327 _elementCount--; 332 _elementCount--;
328 return true; 333 return true;
329 } 334 }
330 entry = entry._nextLink; 335 entry = entry._nextLink;
331 } 336 }
332 return false; 337 return false;
333 } 338 }
334 339
335 void _filter(bool test(E element), bool removeMatching) { 340 void _filter(bool test(E element), bool removeMatching) {
336 _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink; 341 _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
337 while (!identical(entry, _sentinel)) { 342 while (!identical(entry, _sentinel)) {
338 _DoubleLinkedQueueEntry<E> next = entry._nextLink; 343 bool matches = test(entry._element);
339 if (identical(removeMatching, test(entry._element))) { 344 if (!identical(this, entry._queue)) {
345 // Entry must still be in the queue.
346 throw new ConcurrentModificationError(this);
347 }
348 _DoubleLinkedQueueEntry<E> next = entry._nextLink; // Cannot be null.
349 if (identical(removeMatching, matches)) {
340 entry._remove(); 350 entry._remove();
341 _elementCount--; 351 _elementCount--;
342 } 352 }
343 entry = next; 353 entry = next;
344 } 354 }
345 } 355 }
346 356
347 void removeWhere(bool test(E element)) { 357 void removeWhere(bool test(E element)) {
348 _filter(test, true); 358 _filter(test, true);
349 } 359 }
350 360
351 void retainWhere(bool test(E element)) { 361 void retainWhere(bool test(E element)) {
352 _filter(test, false); 362 _filter(test, false);
353 } 363 }
354 364
355 E get first { 365 E get first {
356 _DoubleLinkedQueueEntry<E> firstEntry = _sentinel._nextLink; 366 _DoubleLinkedQueueEntry<E> firstEntry = _sentinel._nextLink;
357 return firstEntry._element; 367 return firstEntry._element;
358 } 368 }
359 369
360 E get last { 370 E get last {
361 _DoubleLinkedQueueEntry<E> lastEntry = _sentinel._previousLink; 371 _DoubleLinkedQueueEntry<E> lastEntry = _sentinel._previousLink;
362 return lastEntry._element; 372 return lastEntry._element;
363 } 373 }
364 374
365 E get single { 375 E get single {
366 // Note that this throws correctly if the queue is empty 376 // Note that this throws correctly if the queue is empty
367 // because reading element on the sentinel throws. 377 // because reading the element of the sentinel throws.
368 if (identical(_sentinel._nextLink, _sentinel._previousLink)) { 378 if (identical(_sentinel._nextLink, _sentinel._previousLink)) {
369 _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink; 379 _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
370 return entry._element; 380 return entry._element;
371 } 381 }
372 throw IterableElementError.tooMany(); 382 throw IterableElementError.tooMany();
373 } 383 }
374 384
385 /**
386 * The entry object of the first element in the queue.
387 *
388 * Each element of the queue has an associated [DoubleLinkedQueueEntry].
389 * Returns the entry object corresponding to the first element of the queue.
390 *
391 * The entry objects can also be accessed using [lastEntry],
392 * and they can be iterated using [DoubleLinkedQueueEntry.nextEntry()] and
393 * [DoubleLinkedQueueEntry.previousEntry()].
394 */
395 DoubleLinkedQueueEntry<E> firstEntry() {
396 return _sentinel.nextEntry();
397 }
398
399 /**
400 * The entry object of the last element in the queue.
401 *
402 * Each element of the queue has an associated [DoubleLinkedQueueEntry].
403 * Returns the entry object corresponding to the last element of the queue.
404 *
405 * The entry objects can also be accessed using [firstEntry],
406 * and they can be iterated using [DoubleLinkedQueueEntry.nextEntry()] and
407 * [DoubleLinkedQueueEntry.previousEntry()].
408 */
375 DoubleLinkedQueueEntry<E> lastEntry() { 409 DoubleLinkedQueueEntry<E> lastEntry() {
floitsch 2016/12/01 18:31:09 not a getter? argh :(
376 return _sentinel.previousEntry(); 410 return _sentinel.previousEntry();
377 } 411 }
378 412
379 DoubleLinkedQueueEntry<E> firstEntry() {
380 return _sentinel.nextEntry();
381 }
382
383 bool get isEmpty { 413 bool get isEmpty {
384 return (identical(_sentinel._nextLink, _sentinel)); 414 return (identical(_sentinel._nextLink, _sentinel));
385 } 415 }
386 416
387 void clear() { 417 void clear() {
388 _sentinel._nextLink = _sentinel; 418 _sentinel._nextLink = _sentinel;
389 _sentinel._previousLink = _sentinel; 419 _sentinel._previousLink = _sentinel;
390 _elementCount = 0; 420 _elementCount = 0;
391 } 421 }
392 422
393 void forEachEntry(void f(DoubleLinkedQueueEntry<E> element)) { 423 /**
424 * Calls [action] for each entry object of this double-linked queue.
425 *
426 * Each element of the queue has an associated [DoubleLinkedQueueEntry].
427 * This method iterates the entry objects from first to last and calls
428 * [action] with each object in turn.
429 *
430 * The entry objects can also be accessed using [firstEntry] and [lastEntry],
431 * and iterated using [DoubleLinkedQueueEntry.nextEntry()] and
432 * [DoubleLinkedQueueEntry.previousEntry()].
433 *
434 * The [action] function can use methods on [DoubleLinkedQueueEntry] to remove
435 * the entry or it can insert elements before or after then entry.
436 * If the current entry is removed, iteration continues with the entry that
437 * was following the current entry when [action] was called. Any elements
438 * inserted after the current element before it is removed will not be
439 * visited by the iteration.
440 */
441 void forEachEntry(void action(DoubleLinkedQueueEntry<E> element)) {
394 _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink; 442 _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
395 while (!identical(entry, _sentinel)) { 443 while (!identical(entry, _sentinel)) {
396 _DoubleLinkedQueueEntry<E> nextEntry = entry._nextLink;
397 _DoubleLinkedQueueElement<E> element = entry; 444 _DoubleLinkedQueueElement<E> element = entry;
398 f(element); 445 _DoubleLinkedQueueEntry<E> next = element._nextLink;
399 entry = nextEntry; 446 // Remember both entry and entry._nextLink.
447 // If someone calls `element.remove()` we continue from `next`.
448 // Otherwise we use the value of entry._nextLink which may have been
449 // updated.
450 action(element);
451 if (identical(this, entry._queue)) {
452 next = entry._nextLink;
453 } else if (!identical(this, next._queue)) {
454 throw new ConcurrentModificationError(this);
455 }
456 entry = next;
400 } 457 }
401 } 458 }
402 459
403 _DoubleLinkedQueueIterator<E> get iterator { 460 _DoubleLinkedQueueIterator<E> get iterator {
404 return new _DoubleLinkedQueueIterator<E>(_sentinel); 461 return new _DoubleLinkedQueueIterator<E>(_sentinel);
405 } 462 }
406 463
407 String toString() => IterableBase.iterableToFullString(this, '{', '}'); 464 String toString() => IterableBase.iterableToFullString(this, '{', '}');
408 } 465 }
409 466
410 class _DoubleLinkedQueueIterator<E> implements Iterator<E> { 467 class _DoubleLinkedQueueIterator<E> implements Iterator<E> {
411 _DoubleLinkedQueueSentinel<E> _sentinel; 468 _DoubleLinkedQueueSentinel<E> _sentinel;
412 _DoubleLinkedQueueEntry<E> _nextEntry = null; 469 _DoubleLinkedQueueEntry<E> _nextEntry = null;
413 E _current; 470 E _current;
414 471
415 _DoubleLinkedQueueIterator(_DoubleLinkedQueueSentinel<E> sentinel) 472 _DoubleLinkedQueueIterator(_DoubleLinkedQueueSentinel<E> sentinel)
416 : _sentinel = sentinel, 473 : _sentinel = sentinel,
417 _nextEntry = sentinel._nextLink; 474 _nextEntry = sentinel._nextLink;
418 475
419 bool moveNext() { 476 bool moveNext() {
420 if (identical(_nextEntry, _sentinel)) { 477 if (identical(_nextEntry, _sentinel)) {
421 _current = null; 478 _current = null;
422 _nextEntry = null; 479 _nextEntry = null;
423 _sentinel = null; 480 _sentinel = null;
424 return false; 481 return false;
425 } 482 }
426 _DoubleLinkedQueueElement<E> elementEntry = _nextEntry; 483 _DoubleLinkedQueueElement<E> elementEntry = _nextEntry;
427 if (elementEntry._queue == null) { 484 if (!identical(_sentinel._queue, elementEntry._queue)) {
428 throw new ConcurrentModificationError(_sentinel._queue); 485 throw new ConcurrentModificationError(_sentinel._queue);
429 } 486 }
430 _current = elementEntry._element; 487 _current = elementEntry._element;
431 _nextEntry = elementEntry._nextLink; 488 _nextEntry = elementEntry._nextLink;
432 return true; 489 return true;
433 } 490 }
434 491
435 E get current => _current; 492 E get current => _current;
436 } 493 }
437 494
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after
707 void _add(E element) { 764 void _add(E element) {
708 _table[_tail] = element; 765 _table[_tail] = element;
709 _tail = (_tail + 1) & (_table.length - 1); 766 _tail = (_tail + 1) & (_table.length - 1);
710 if (_head == _tail) _grow(); 767 if (_head == _tail) _grow();
711 _modificationCount++; 768 _modificationCount++;
712 } 769 }
713 770
714 /** 771 /**
715 * Removes the element at [offset] into [_table]. 772 * Removes the element at [offset] into [_table].
716 * 773 *
717 * Removal is performed by linerarly moving elements either before or after 774 * Removal is performed by linearly moving elements either before or after
718 * [offset] by one position. 775 * [offset] by one position.
719 * 776 *
720 * Returns the new offset of the following element. This may be the same 777 * Returns the new offset of the following element. This may be the same
721 * offset or the following offset depending on how elements are moved 778 * offset or the following offset depending on how elements are moved
722 * to fill the hole. 779 * to fill the hole.
723 */ 780 */
724 int _remove(int offset) { 781 int _remove(int offset) {
725 int mask = _table.length - 1; 782 int mask = _table.length - 1;
726 int startDistance = (offset - _head) & mask; 783 int startDistance = (offset - _head) & mask;
727 int endDistance = (_tail - offset) & mask; 784 int endDistance = (_tail - offset) & mask;
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
815 _queue._checkModification(_modificationCount); 872 _queue._checkModification(_modificationCount);
816 if (_position == _end) { 873 if (_position == _end) {
817 _current = null; 874 _current = null;
818 return false; 875 return false;
819 } 876 }
820 _current = _queue._table[_position]; 877 _current = _queue._table[_position];
821 _position = (_position + 1) & (_queue._table.length - 1); 878 _position = (_position + 1) & (_queue._table.length - 1);
822 return true; 879 return true;
823 } 880 }
824 } 881 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/core/num.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698