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]. |
11 * | 11 * |
12 * It is generally not allowed to modify the queue (add or remove entries) while | 12 * It is generally not allowed to modify the queue (add or remove entries) while |
13 * an operation on the queue is being performed, for example during a call to | 13 * an operation on the queue is being performed, for example during a call to |
14 * [forEach]. | 14 * [forEach]. |
15 * Modifying the queue while it is being iterated will most likely break the | 15 * Modifying the queue while it is being iterated will most likely break the |
16 * iteration. | 16 * iteration. |
17 * This goes both for using the [iterator] directly, or for iterating an | 17 * This goes both for using the [iterator] directly, or for iterating an |
18 * `Iterable` returned by a method like [map] or [where]. | 18 * `Iterable` returned by a method like [map] or [where]. |
19 */ | 19 */ |
20 abstract class Queue<E> implements EfficientLengthIterable<E> { | 20 abstract class Queue<E> implements EfficientLengthIterable<E> { |
21 | |
22 /** | 21 /** |
23 * Creates a queue. | 22 * Creates a queue. |
24 */ | 23 */ |
25 factory Queue() = ListQueue<E>; | 24 factory Queue() = ListQueue<E>; |
26 | 25 |
27 /** | 26 /** |
28 * Creates a queue containing all [elements]. | 27 * Creates a queue containing all [elements]. |
29 * | 28 * |
30 * The element order in the queue is as if the elements were added using | 29 * The element order in the queue is as if the elements were added using |
31 * [addLast] in the order provided by [elements.iterator]. | 30 * [addLast] in the order provided by [elements.iterator]. |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 * The `test` function must not throw or modify the queue. | 87 * The `test` function must not throw or modify the queue. |
89 */ | 88 */ |
90 void retainWhere(bool test(E element)); | 89 void retainWhere(bool test(E element)); |
91 | 90 |
92 /** | 91 /** |
93 * Removes all elements in the queue. The size of the queue becomes zero. | 92 * Removes all elements in the queue. The size of the queue becomes zero. |
94 */ | 93 */ |
95 void clear(); | 94 void clear(); |
96 } | 95 } |
97 | 96 |
98 | |
99 class _DoubleLink<Link extends _DoubleLink> { | 97 class _DoubleLink<Link extends _DoubleLink> { |
100 Link _previousLink; | 98 Link _previousLink; |
101 Link _nextLink; | 99 Link _nextLink; |
102 | 100 |
103 void _link(Link previous, Link next) { | 101 void _link(Link previous, Link next) { |
104 _nextLink = next; | 102 _nextLink = next; |
105 _previousLink = previous; | 103 _previousLink = previous; |
106 if (previous != null) previous._nextLink = this; | 104 if (previous != null) previous._nextLink = this; |
107 if (next != null) next._previousLink = this; | 105 if (next != null) next._previousLink = this; |
108 } | 106 } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
148 } | 146 } |
149 | 147 |
150 /** | 148 /** |
151 * Interface for the link classes used by [DoubleLinkedQueue]. | 149 * Interface for the link classes used by [DoubleLinkedQueue]. |
152 * | 150 * |
153 * Both the [_DoubleLinkedQueueElement] and [_DoubleLinkedQueueSentinel] | 151 * Both the [_DoubleLinkedQueueElement] and [_DoubleLinkedQueueSentinel] |
154 * implement this interface. | 152 * implement this interface. |
155 * The entry contains a link back to the queue, so calling `append` | 153 * The entry contains a link back to the queue, so calling `append` |
156 * or `prepend` can correctly update the element count. | 154 * or `prepend` can correctly update the element count. |
157 */ | 155 */ |
158 abstract class _DoubleLinkedQueueEntry<E> | 156 abstract class _DoubleLinkedQueueEntry<E> extends DoubleLinkedQueueEntry<E> { |
159 extends DoubleLinkedQueueEntry<E> { | |
160 DoubleLinkedQueue<E> _queue; | 157 DoubleLinkedQueue<E> _queue; |
161 _DoubleLinkedQueueEntry(E element, this._queue) : super(element); | 158 _DoubleLinkedQueueEntry(E element, this._queue) : super(element); |
162 | 159 |
163 DoubleLinkedQueueEntry<E> _asNonSentinelEntry(); | 160 DoubleLinkedQueueEntry<E> _asNonSentinelEntry(); |
164 | 161 |
165 void _append(E e) { | 162 void _append(E e) { |
166 new _DoubleLinkedQueueElement<E>(e, _queue)._link(this, _nextLink); | 163 new _DoubleLinkedQueueElement<E>(e, _queue)._link(this, _nextLink); |
167 } | 164 } |
168 | 165 |
169 void _prepend(E e) { | 166 void _prepend(E e) { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 | 222 |
226 /** | 223 /** |
227 * A sentinel in a double linked list is used to manipulate the list | 224 * A sentinel in a double linked list is used to manipulate the list |
228 * at both ends. | 225 * at both ends. |
229 * A double linked list has exactly one sentinel, | 226 * A double linked list has exactly one sentinel, |
230 * which is the only entry when the list is constructed. | 227 * which is the only entry when the list is constructed. |
231 * Initially, a sentinel has its next and previous entry point to itself. | 228 * Initially, a sentinel has its next and previous entry point to itself. |
232 * A sentinel does not box any user element. | 229 * A sentinel does not box any user element. |
233 */ | 230 */ |
234 class _DoubleLinkedQueueSentinel<E> extends _DoubleLinkedQueueEntry<E> { | 231 class _DoubleLinkedQueueSentinel<E> extends _DoubleLinkedQueueEntry<E> { |
235 _DoubleLinkedQueueSentinel(DoubleLinkedQueue<E> queue) | 232 _DoubleLinkedQueueSentinel(DoubleLinkedQueue<E> queue) : super(null, queue) { |
236 : super(null, queue) { | |
237 _previousLink = this; | 233 _previousLink = this; |
238 _nextLink = this; | 234 _nextLink = this; |
239 } | 235 } |
240 | 236 |
241 DoubleLinkedQueueEntry<E> _asNonSentinelEntry() { | 237 DoubleLinkedQueueEntry<E> _asNonSentinelEntry() { |
242 return null; | 238 return null; |
243 } | 239 } |
244 | 240 |
245 /** Hit by, e.g., [DoubleLinkedQueue.removeFirst] if the queue is empty. */ | 241 /** Hit by, e.g., [DoubleLinkedQueue.removeFirst] if the queue is empty. */ |
246 E _remove() { | 242 E _remove() { |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
338 } | 334 } |
339 | 335 |
340 void _filter(bool test(E element), bool removeMatching) { | 336 void _filter(bool test(E element), bool removeMatching) { |
341 _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink; | 337 _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink; |
342 while (!identical(entry, _sentinel)) { | 338 while (!identical(entry, _sentinel)) { |
343 bool matches = test(entry._element); | 339 bool matches = test(entry._element); |
344 if (!identical(this, entry._queue)) { | 340 if (!identical(this, entry._queue)) { |
345 // Entry must still be in the queue. | 341 // Entry must still be in the queue. |
346 throw new ConcurrentModificationError(this); | 342 throw new ConcurrentModificationError(this); |
347 } | 343 } |
348 _DoubleLinkedQueueEntry<E> next = entry._nextLink; // Cannot be null. | 344 _DoubleLinkedQueueEntry<E> next = entry._nextLink; // Cannot be null. |
349 if (identical(removeMatching, matches)) { | 345 if (identical(removeMatching, matches)) { |
350 entry._remove(); | 346 entry._remove(); |
351 _elementCount--; | 347 _elementCount--; |
352 } | 348 } |
353 entry = next; | 349 entry = next; |
354 } | 350 } |
355 } | 351 } |
356 | 352 |
357 void removeWhere(bool test(E element)) { | 353 void removeWhere(bool test(E element)) { |
358 _filter(test, true); | 354 _filter(test, true); |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
507 int _head; | 503 int _head; |
508 int _tail; | 504 int _tail; |
509 int _modificationCount = 0; | 505 int _modificationCount = 0; |
510 | 506 |
511 /** | 507 /** |
512 * Create an empty queue. | 508 * Create an empty queue. |
513 * | 509 * |
514 * If [initialCapacity] is given, prepare the queue for at least that many | 510 * If [initialCapacity] is given, prepare the queue for at least that many |
515 * elements. | 511 * elements. |
516 */ | 512 */ |
517 ListQueue([int initialCapacity]) : _head = 0, _tail = 0 { | 513 ListQueue([int initialCapacity]) |
| 514 : _head = 0, |
| 515 _tail = 0 { |
518 if (initialCapacity == null || initialCapacity < _INITIAL_CAPACITY) { | 516 if (initialCapacity == null || initialCapacity < _INITIAL_CAPACITY) { |
519 initialCapacity = _INITIAL_CAPACITY; | 517 initialCapacity = _INITIAL_CAPACITY; |
520 } else if (!_isPowerOf2(initialCapacity)) { | 518 } else if (!_isPowerOf2(initialCapacity)) { |
521 initialCapacity = _nextPowerOf2(initialCapacity); | 519 initialCapacity = _nextPowerOf2(initialCapacity); |
522 } | 520 } |
523 assert(_isPowerOf2(initialCapacity)); | 521 assert(_isPowerOf2(initialCapacity)); |
524 _table = new List<E>(initialCapacity); | 522 _table = new List<E>(initialCapacity); |
525 } | 523 } |
526 | 524 |
527 /** | 525 /** |
(...skipping 24 matching lines...) Expand all Loading... |
552 result.addLast(element as Object/*=E*/); | 550 result.addLast(element as Object/*=E*/); |
553 } | 551 } |
554 return result; | 552 return result; |
555 } | 553 } |
556 } | 554 } |
557 | 555 |
558 // Iterable interface. | 556 // Iterable interface. |
559 | 557 |
560 Iterator<E> get iterator => new _ListQueueIterator<E>(this); | 558 Iterator<E> get iterator => new _ListQueueIterator<E>(this); |
561 | 559 |
562 void forEach(void action (E element)) { | 560 void forEach(void action(E element)) { |
563 int modificationCount = _modificationCount; | 561 int modificationCount = _modificationCount; |
564 for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) { | 562 for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) { |
565 action(_table[i]); | 563 action(_table[i]); |
566 _checkModification(modificationCount); | 564 _checkModification(modificationCount); |
567 } | 565 } |
568 } | 566 } |
569 | 567 |
570 bool get isEmpty => _head == _tail; | 568 bool get isEmpty => _head == _tail; |
571 | 569 |
572 int get length => (_tail - _head) & (_table.length - 1); | 570 int get length => (_tail - _head) & (_table.length - 1); |
(...skipping 12 matching lines...) Expand all Loading... |
585 if (_head == _tail) throw IterableElementError.noElement(); | 583 if (_head == _tail) throw IterableElementError.noElement(); |
586 if (length > 1) throw IterableElementError.tooMany(); | 584 if (length > 1) throw IterableElementError.tooMany(); |
587 return _table[_head]; | 585 return _table[_head]; |
588 } | 586 } |
589 | 587 |
590 E elementAt(int index) { | 588 E elementAt(int index) { |
591 RangeError.checkValidIndex(index, this); | 589 RangeError.checkValidIndex(index, this); |
592 return _table[(_head + index) & (_table.length - 1)]; | 590 return _table[(_head + index) & (_table.length - 1)]; |
593 } | 591 } |
594 | 592 |
595 List<E> toList({ bool growable: true }) { | 593 List<E> toList({bool growable: true}) { |
596 List<E> list; | 594 List<E> list; |
597 if (growable) { | 595 if (growable) { |
598 list = new List<E>()..length = length; | 596 list = new List<E>()..length = length; |
599 } else { | 597 } else { |
600 list = new List<E>(length); | 598 list = new List<E>(length); |
601 } | 599 } |
602 _writeToList(list); | 600 _writeToList(list); |
603 return list; | 601 return list; |
604 } | 602 } |
605 | 603 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
693 } | 691 } |
694 _head = _tail = 0; | 692 _head = _tail = 0; |
695 _modificationCount++; | 693 _modificationCount++; |
696 } | 694 } |
697 } | 695 } |
698 | 696 |
699 String toString() => IterableBase.iterableToFullString(this, "{", "}"); | 697 String toString() => IterableBase.iterableToFullString(this, "{", "}"); |
700 | 698 |
701 // Queue interface. | 699 // Queue interface. |
702 | 700 |
703 void addLast(E value) { _add(value); } | 701 void addLast(E value) { |
| 702 _add(value); |
| 703 } |
704 | 704 |
705 void addFirst(E value) { | 705 void addFirst(E value) { |
706 _head = (_head - 1) & (_table.length - 1); | 706 _head = (_head - 1) & (_table.length - 1); |
707 _table[_head] = value; | 707 _table[_head] = value; |
708 if (_head == _tail) _grow(); | 708 if (_head == _tail) _grow(); |
709 _modificationCount++; | 709 _modificationCount++; |
710 } | 710 } |
711 | 711 |
712 E removeFirst() { | 712 E removeFirst() { |
713 if (_head == _tail) throw IterableElementError.noElement(); | 713 if (_head == _tail) throw IterableElementError.noElement(); |
(...skipping 25 matching lines...) Expand all Loading... |
739 /** | 739 /** |
740 * Rounds [number] up to the nearest power of 2. | 740 * Rounds [number] up to the nearest power of 2. |
741 * | 741 * |
742 * If [number] is a power of 2 already, it is returned. | 742 * If [number] is a power of 2 already, it is returned. |
743 * | 743 * |
744 * Only works for positive numbers. | 744 * Only works for positive numbers. |
745 */ | 745 */ |
746 static int _nextPowerOf2(int number) { | 746 static int _nextPowerOf2(int number) { |
747 assert(number > 0); | 747 assert(number > 0); |
748 number = (number << 1) - 1; | 748 number = (number << 1) - 1; |
749 for(;;) { | 749 for (;;) { |
750 int nextNumber = number & (number - 1); | 750 int nextNumber = number & (number - 1); |
751 if (nextNumber == 0) return number; | 751 if (nextNumber == 0) return number; |
752 number = nextNumber; | 752 number = nextNumber; |
753 } | 753 } |
754 } | 754 } |
755 | 755 |
756 /** Check if the queue has been modified during iteration. */ | 756 /** Check if the queue has been modified during iteration. */ |
757 void _checkModification(int expectedModificationCount) { | 757 void _checkModification(int expectedModificationCount) { |
758 if (expectedModificationCount != _modificationCount) { | 758 if (expectedModificationCount != _modificationCount) { |
759 throw new ConcurrentModificationError(this); | 759 throw new ConcurrentModificationError(this); |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
872 _queue._checkModification(_modificationCount); | 872 _queue._checkModification(_modificationCount); |
873 if (_position == _end) { | 873 if (_position == _end) { |
874 _current = null; | 874 _current = null; |
875 return false; | 875 return false; |
876 } | 876 } |
877 _current = _queue._table[_position]; | 877 _current = _queue._table[_position]; |
878 _position = (_position + 1) & (_queue._table.length - 1); | 878 _position = (_position + 1) & (_queue._table.length - 1); |
879 return true; | 879 return true; |
880 } | 880 } |
881 } | 881 } |
OLD | NEW |