Chromium Code Reviews| 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 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |