// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. part of "dart:collection"; /// Helper interface to hide [EfficientLengthIterable] from the public /// declaration of [Queue]. abstract class _QueueIterable implements EfficientLengthIterable, HideEfficientLengthIterable {} /// A [Queue] is a collection that can be manipulated at both ends. One /// can iterate over the elements of a queue through [forEach] or with /// an [Iterator]. /// /// It is generally not allowed to modify the queue (add or remove entries) /// while an operation in the queue is being performed, for example during a /// call to [forEach]. /// Modifying the queue while it is being iterated will most likely break the /// iteration. /// This goes both for using the [iterator] directly, or for iterating an /// `Iterable` returned by a method like [map] or [where]. /// /// Example: /// ```dart /// final queue = Queue(); // ListQueue() by default /// print(queue.runtimeType); // ListQueue /// /// // Adding items to queue /// queue.addAll([1, 2, 3]); /// queue.addFirst(0); /// queue.addLast(10); /// print(queue); // {0, 1, 2, 3, 10} /// /// // Removing items from queue /// queue.removeFirst(); /// queue.removeLast(); /// print(queue); // {1, 2, 3} /// ``` abstract interface class Queue implements Iterable, _QueueIterable { /// Creates a queue. factory Queue() = ListQueue; /// Creates a queue containing all [elements]. /// /// The element order in the queue is as if the elements were added using /// [addLast] in the order provided by [elements].iterator. /// /// All the [elements] should be instances of [E]. /// The `elements` iterable itself may have any element type, so this /// constructor can be used to down-cast a `Queue`, for example as: /// ```dart /// Queue superQueue = ...; /// Queue subQueue = /// Queue.from(superQueue.whereType()); /// ``` factory Queue.from(Iterable elements) = ListQueue.from; /// Creates a queue from [elements]. /// /// The element order in the queue is as if the elements were added using /// [addLast] in the order provided by [elements].iterator. factory Queue.of(Iterable elements) = ListQueue.of; /// Adapts [source] to be a `Queue`. /// /// Any time the queue would produce an element that is not a [T], /// the element access will throw. /// /// When a [T] value is stored into the adapted queue, /// the operation will throw unless the value is also an instance of [S]. /// /// If all accessed elements of [source] are actually instances of [T], /// and if all elements stored into the returned queue are actually instances /// of [S], /// then the returned queue can be used as a `Queue`. /// /// Methods which accept `Object?` as argument, like [contains] and [remove], /// will pass the argument directly to this queue's method /// without any checks. static Queue castFrom(Queue source) => CastQueue(source); /// Provides a view of this queue as a queue of [R] instances, if necessary. /// /// If this queue contains only instances of [R], all read operations /// will work correctly. If any operation tries to access an element /// that is not an instance of [R], the access will throw instead. /// /// Elements added to the queue (e.g., by using [addFirst] or [addAll]) /// must be instances of [R] to be valid arguments to the adding function, /// and they must also be instances of [E] to be accepted by /// this queue as well. /// /// Methods which accept `Object?` as argument, like [contains] and [remove], /// will pass the argument directly to the this queue's method /// without any checks. /// That means that you can do `queueOfStrings.cast().remove("a")` /// successfully, even if it looks like it shouldn't have any effect. Queue cast(); /// Removes and returns the first element of this queue. /// /// The queue must not be empty when this method is called. E removeFirst(); /// Removes and returns the last element of the queue. /// /// The queue must not be empty when this method is called. E removeLast(); /// Adds [value] at the beginning of the queue. void addFirst(E value); /// Adds [value] at the end of the queue. void addLast(E value); /// Adds [value] at the end of the queue. void add(E value); /// Removes a single instance of [value] from the queue. /// /// Returns `true` if a value was removed, or `false` if the queue /// contained no element equal to [value]. bool remove(Object? value); /// Adds all elements of [iterable] at the end of the queue. The /// length of the queue is extended by the length of [iterable]. void addAll(Iterable iterable); /// Removes all elements matched by [test] from the queue. /// /// The `test` function must not throw or modify the queue. void removeWhere(bool test(E element)); /// Removes all elements not matched by [test] from the queue. /// /// The `test` function must not throw or modify the queue. void retainWhere(bool test(E element)); /// Removes all elements in the queue. The size of the queue becomes zero. void clear(); } /// Interface and base class for the link classes used by [DoubleLinkedQueue]. /// /// Both the [_DoubleLinkedQueueElement] and [_DoubleLinkedQueueSentinel] /// implement this interface. abstract class _DoubleLinkedQueueEntry { _DoubleLinkedQueueEntry? _previousLink; _DoubleLinkedQueueEntry? _nextLink; void _link( _DoubleLinkedQueueEntry? previous, _DoubleLinkedQueueEntry? next, ) { _nextLink = next; _previousLink = previous; previous?._nextLink = this; next?._previousLink = this; } void _unlink() { _previousLink?._nextLink = _nextLink; _nextLink?._previousLink = _previousLink; _previousLink = _nextLink = null; } _DoubleLinkedQueueElement? _asNonSentinelEntry(); void _append(E element, DoubleLinkedQueue? queue) { _DoubleLinkedQueueElement(element, queue)._link(this, _nextLink); } void _prepend(E element, DoubleLinkedQueue? queue) { _DoubleLinkedQueueElement(element, queue)._link(_previousLink, this); } E _remove(); E get element; } /// Linked list entry used by the [DoubleLinkedQueue] to hold an element. /// /// These entry objects are also exposed by [DoubleLinkedQueue.firstEntry], /// [DoubleLinkedQueue.lastEntry] and [DoubleLinkedQueue.forEachEntry]. /// /// The entry contains both the [element] (which is mutable to anyone with /// access to the entry object) and a reference to the queue, allowing /// [append]/[prepend] to update the list length. /// /// When an entry is removed from its queue, the [_queue] is set to `null` /// and will never change again. You can still use the unlinked entry /// to create a new list, by calling [append] and [prepend], but it won't /// be part of any [DoubleLinkedQueue]. class _DoubleLinkedQueueElement extends _DoubleLinkedQueueEntry implements DoubleLinkedQueueEntry { DoubleLinkedQueue? _queue; E element; _DoubleLinkedQueueElement(this.element, this._queue); void append(E e) { _append(e, _queue); _queue?._elementCount++; } void prepend(E e) { _prepend(e, _queue); _queue?._elementCount++; } E _remove() { _queue = null; _unlink(); return element; } E remove() { _queue?._elementCount--; return _remove(); } _DoubleLinkedQueueElement _asNonSentinelEntry() => this; DoubleLinkedQueueEntry? previousEntry() => _previousLink?._asNonSentinelEntry(); DoubleLinkedQueueEntry? nextEntry() => _nextLink?._asNonSentinelEntry(); } /// A header object used to hold the two ends of a double linked queue. /// /// A [DoubleLinkedQueue] has exactly one sentinel, /// which is the only entry when the list is constructed. /// /// Initially, a sentinel has its next and previous entries point to itself. /// Its next and previous links are never `null` after creation, and /// the entries linked always form a circular structure with the next link /// pointing to the first element of the queue, and the previous link /// pointing to the last element of the queue, or both pointing to itself /// again if the queue becomes empty. /// /// Implements [_DoubleLinkedQueueEntry._remove] and /// [_DoubleLinkedQueueEntry.element] as throwing because /// it makes it simple to implement members like [Queue.removeFirst] /// or [Queue.first] as throwing on an empty queue. /// /// A sentinel does not contain any user element. class _DoubleLinkedQueueSentinel extends _DoubleLinkedQueueEntry { _DoubleLinkedQueueSentinel() { _previousLink = this; _nextLink = this; } Null _asNonSentinelEntry() => null; /// Hit by, e.g., [DoubleLinkedQueue.removeFirst] if the queue is empty. E _remove() { throw IterableElementError.noElement(); } /// Hit by, e.g., [DoubleLinkedQueue.first] if the queue is empty. E get element { throw IterableElementError.noElement(); } } /// A [Queue] implementation based on a double-linked list. /// /// Allows constant time add, remove-at-ends and peek operations. final class DoubleLinkedQueue extends Iterable implements Queue { final _DoubleLinkedQueueSentinel _sentinel = _DoubleLinkedQueueSentinel(); int _elementCount = 0; DoubleLinkedQueue(); /// Creates a double-linked queue containing all [elements]. /// /// The element order in the queue is as if the elements were added using /// [addLast] in the order provided by [elements].iterator. /// /// All the [elements] should be instances of [E]. /// The [elements] iterable itself may have any element type, so this /// constructor can be used to down-cast a [Queue], for example as: /// ```dart /// Queue superQueue = ...; /// Queue subQueue = /// DoubleLinkedQueue.from(superQueue.whereType()); /// ``` factory DoubleLinkedQueue.from(Iterable elements) { DoubleLinkedQueue list = DoubleLinkedQueue(); for (final e in elements) { list.addLast(e as E); } return list; } /// Creates a double-linked queue from [elements]. /// /// The element order in the queue is as if the elements were added using /// [addLast] in the order provided by [elements].iterator. factory DoubleLinkedQueue.of(Iterable elements) => DoubleLinkedQueue()..addAll(elements); Queue cast() => Queue.castFrom(this); int get length => _elementCount; void addLast(E value) { _sentinel._prepend(value, this); _elementCount++; } void addFirst(E value) { _sentinel._append(value, this); _elementCount++; } void add(E value) { _sentinel._prepend(value, this); _elementCount++; } void addAll(Iterable iterable) { for (final E value in iterable) { _sentinel._prepend(value, this); _elementCount++; } } E removeLast() { // Hits sentinel's `_remove` if queue is empty. E result = _sentinel._previousLink!._remove(); _elementCount--; return result; } E removeFirst() { // Hits sentinel's `_remove` if queue is empty. E result = _sentinel._nextLink!._remove(); _elementCount--; return result; } bool remove(Object? o) { _DoubleLinkedQueueEntry entry = _sentinel._nextLink!; while (true) { var elementEntry = entry._asNonSentinelEntry(); if (elementEntry == null) return false; bool equals = (elementEntry.element == o); if (!identical(this, elementEntry._queue)) { // Entry must still be in the queue. throw ConcurrentModificationError(this); } if (equals) { entry._remove(); _elementCount--; return true; } entry = entry._nextLink!; } } void _filter(bool test(E element), bool removeMatching) { _DoubleLinkedQueueEntry entry = _sentinel._nextLink!; while (true) { var elementEntry = entry._asNonSentinelEntry(); if (elementEntry == null) return; bool matches = test(elementEntry.element); if (!identical(this, elementEntry._queue)) { // Entry must still be in the queue. throw ConcurrentModificationError(this); } var next = entry._nextLink!; // Cannot be null while entry is in queue. if (identical(removeMatching, matches)) { elementEntry._remove(); _elementCount--; } entry = next; } } void removeWhere(bool test(E element)) { _filter(test, true); } void retainWhere(bool test(E element)) { _filter(test, false); } // Hits sentinel's `get element` if no element in queue. E get first => _sentinel._nextLink!.element; // Hits sentinel's `get element` if no element in queue. E get last => _sentinel._previousLink!.element; E get single { // Note that this throws correctly if the queue is empty // because reading the element of the sentinel throws. if (identical(_sentinel._nextLink, _sentinel._previousLink)) { return _sentinel._nextLink!.element; } throw IterableElementError.tooMany(); } /// 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, /// or `null` if the queue is empty. /// /// The entry objects can also be accessed using [lastEntry], /// and they can be iterated using [DoubleLinkedQueueEntry.nextEntry] and /// [DoubleLinkedQueueEntry.previousEntry]. DoubleLinkedQueueEntry? firstEntry() => _sentinel._nextLink!._asNonSentinelEntry(); /// 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, /// or `null` if the queue is empty. /// /// The entry objects can also be accessed using [firstEntry], /// and they can be iterated using [DoubleLinkedQueueEntry.nextEntry] and /// [DoubleLinkedQueueEntry.previousEntry]. DoubleLinkedQueueEntry? lastEntry() => _sentinel._previousLink!._asNonSentinelEntry(); bool get isEmpty => identical(_sentinel._nextLink, _sentinel); void clear() { var cursor = _sentinel._nextLink!; while (true) { var entry = cursor._asNonSentinelEntry(); if (entry == null) break; cursor = cursor._nextLink!; entry .._nextLink = null .._previousLink = null .._queue = null; } _sentinel._nextLink = _sentinel; _sentinel._previousLink = _sentinel; _elementCount = 0; } /// 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 the 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 element)) { var cursor = _sentinel._nextLink!; while (true) { var element = cursor._asNonSentinelEntry(); if (element == null) break; if (!identical(element._queue, this)) { throw ConcurrentModificationError(this); } cursor = cursor._nextLink!; // Remember both element and element._nextLink (as cursor). // If someone calls `element.remove()` we continue from `next`. // Otherwise we use the value of element._nextLink which may have been // updated. action(element); if (identical(this, element._queue)) { cursor = element._nextLink!; } } } _DoubleLinkedQueueIterator get iterator { return _DoubleLinkedQueueIterator(this); } String toString() => Iterable.iterableToFullString(this, '{', '}'); } class _DoubleLinkedQueueIterator implements Iterator { /// Queue being iterated. Used for concurrent modification checks. DoubleLinkedQueue? _queue; /// Next entry to visit. Set to null when hitting the sentinel. _DoubleLinkedQueueEntry? _nextEntry; /// Current element value, when valid. E? _current; _DoubleLinkedQueueIterator(DoubleLinkedQueue this._queue) : _nextEntry = _queue._sentinel._nextLink; bool moveNext() { var nextElement = _nextEntry?._asNonSentinelEntry(); if (nextElement == null) { // Clear everything to not unnecessarily keep values alive. _current = null; _nextEntry = null; _queue = null; return false; } if (!identical(_queue, nextElement._queue)) { throw ConcurrentModificationError(_queue); } _current = nextElement.element; _nextEntry = nextElement._nextLink; return true; } E get current => _current as E; } /// List based [Queue]. /// /// Keeps a cyclic buffer of elements, and grows to a larger buffer when /// it fills up. This guarantees constant time peek and remove operations, and /// amortized constant time add operations. /// /// The structure is efficient for any queue or stack usage. /// /// Example: /// ```dart /// final queue = ListQueue(); /// ``` /// To add objects to a queue, use [add], [addAll], [addFirst] or[addLast]. /// ```dart continued /// queue.add(5); /// queue.addFirst(0); /// queue.addLast(10); /// queue.addAll([1, 2, 3]); /// print(queue); // {0, 5, 10, 1, 2, 3} /// ``` /// To check if the queue is empty, use [isEmpty] or [isNotEmpty]. /// To find the number of queue entries, use [length]. /// ```dart continued /// final isEmpty = queue.isEmpty; // false /// final queueSize = queue.length; // 6 /// ``` /// To get first or last item from queue, use [first] or [last]. /// ```dart continued /// final first = queue.first; // 0 /// final last = queue.last; // 3 /// ``` /// To get item value using index, use [elementAt]. /// ```dart continued /// final itemAt = queue.elementAt(2); // 10 /// ``` /// To convert queue to list, call [toList]. /// ```dart continued /// final numbers = queue.toList(); /// print(numbers); // [0, 5, 10, 1, 2, 3] /// ``` /// To remove item from queue, call [remove], [removeFirst] or [removeLast]. /// ```dart continued /// queue.remove(10); /// queue.removeFirst(); /// queue.removeLast(); /// print(queue); // {5, 1, 2} /// ``` /// To remove multiple elements at the same time, use [removeWhere]. /// ```dart continued /// queue.removeWhere((element) => element == 1); /// print(queue); // {5, 2} /// ``` /// To remove all elements in this queue that do not meet a condition, /// use [retainWhere]. /// ```dart continued /// queue.retainWhere((element) => element < 4); /// print(queue); // {2} /// ``` /// To remove all items and empty the set, use [clear]. /// ```dart continued /// queue.clear(); /// print(queue.isEmpty); // true /// print(queue); // {} /// ``` final class ListQueue extends ListIterable implements Queue { static const int _INITIAL_CAPACITY = 8; List _table; int _head; int _tail; int _modificationCount = 0; /// Create an empty queue. /// /// If [initialCapacity] is given, prepare the queue for at least that many /// elements. ListQueue([int? initialCapacity]) : _head = 0, _tail = 0, _table = List.filled(_calculateCapacity(initialCapacity), null); static int _calculateCapacity(int? initialCapacity) { if (initialCapacity == null || initialCapacity < _INITIAL_CAPACITY) { return _INITIAL_CAPACITY; } else if (!_isPowerOf2(initialCapacity)) { return _nextPowerOf2(initialCapacity); } assert(_isPowerOf2(initialCapacity)); return initialCapacity; } /// Create a `ListQueue` containing all [elements]. /// /// The elements are added to the queue, as by [addLast], in the order given /// by `elements.iterator`. /// /// All the [elements] should be instances of [E]. /// The `elements` iterable itself may have any element type, so this /// constructor can be used to down-cast a `Queue`, for example as: /// ```dart /// Queue superQueue = ...; /// Queue subQueue = /// ListQueue.from(superQueue.whereType()); /// ``` /// Example: /// ```dart /// final numbers = [10, 20, 30]; /// final queue = ListQueue.from(numbers); /// print(queue); // {10, 20, 30} /// ``` factory ListQueue.from(Iterable elements) { if (elements is List) { int length = elements.length; ListQueue queue = ListQueue(length + 1); assert(queue._table.length > length); for (int i = 0; i < length; i++) { queue._table[i] = elements[i] as E; } queue._tail = length; return queue; } else { int capacity = _INITIAL_CAPACITY; if (elements is EfficientLengthIterable) { capacity = elements.length; } ListQueue result = ListQueue(capacity); for (final element in elements) { result.addLast(element as E); } return result; } } /// Create a `ListQueue` from [elements]. /// /// The elements are added to the queue, as by [addLast], in the order given /// by `elements.iterator`. /// Example: /// ```dart /// final baseQueue = ListQueue.of([1.0, 2.0, 3.0]); // A ListQueue /// final numQueue = ListQueue.of(baseQueue); /// print(numQueue); // {1.0, 2.0, 3.0} /// ``` factory ListQueue.of(Iterable elements) => ListQueue()..addAll(elements); // Iterable interface. Queue cast() => Queue.castFrom(this); Iterator get iterator => _ListQueueIterator(this); void forEach(void f(E element)) { int modificationCount = _modificationCount; for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) { f(_table[i] as E); _checkModification(modificationCount); } } bool get isEmpty => _head == _tail; int get length => (_tail - _head) & (_table.length - 1); E get first { if (_head == _tail) throw IterableElementError.noElement(); return _table[_head] as E; } E get last { if (_head == _tail) throw IterableElementError.noElement(); return _table[(_tail - 1) & (_table.length - 1)] as E; } E get single { if (_head == _tail) throw IterableElementError.noElement(); if (length > 1) throw IterableElementError.tooMany(); return _table[_head] as E; } E elementAt(int index) { IndexError.check(index, length, indexable: this); return _table[(_head + index) & (_table.length - 1)] as E; } List toList({bool growable = true}) { int mask = _table.length - 1; int length = (_tail - _head) & mask; if (length == 0) return List.empty(growable: growable); var list = List.filled(length, first, growable: growable); for (int i = 0; i < length; i++) { list[i] = _table[(_head + i) & mask] as E; } return list; } // Collection interface. void add(E value) { _add(value); } void addAll(Iterable elements) { if (elements is List) { List list = elements; int addCount = list.length; int length = this.length; if (length + addCount >= _table.length) { _preGrow(length + addCount); // After preGrow, all elements are at the start of the list. _table.setRange(length, length + addCount, list, 0); _tail += addCount; } else { // Adding addCount elements won't reach _head. int endSpace = _table.length - _tail; if (addCount < endSpace) { _table.setRange(_tail, _tail + addCount, list, 0); _tail += addCount; } else { int preSpace = addCount - endSpace; _table.setRange(_tail, _tail + endSpace, list, 0); _table.setRange(0, preSpace, list, endSpace); _tail = preSpace; } } _modificationCount++; } else { for (E element in elements) _add(element); } } bool remove(Object? value) { for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) { E? element = _table[i]; if (element == value) { _remove(i); _modificationCount++; return true; } } return false; } void _filterWhere(bool test(E element), bool removeMatching) { int modificationCount = _modificationCount; int i = _head; while (i != _tail) { E element = _table[i] as E; bool remove = identical(removeMatching, test(element)); _checkModification(modificationCount); if (remove) { i = _remove(i); modificationCount = ++_modificationCount; } else { i = (i + 1) & (_table.length - 1); } } } /// Remove all elements matched by [test]. /// /// This method is inefficient since it works by repeatedly removing single /// elements, each of which can take linear time. void removeWhere(bool test(E element)) { _filterWhere(test, true); } /// Remove all elements not matched by [test]. /// /// This method is inefficient since it works by repeatedly removing single /// elements, each of which can take linear time. void retainWhere(bool test(E element)) { _filterWhere(test, false); } void clear() { if (_head != _tail) { for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) { _table[i] = null; } _head = _tail = 0; _modificationCount++; } } String toString() => Iterable.iterableToFullString(this, "{", "}"); // Queue interface. void addLast(E value) { _add(value); } void addFirst(E value) { _head = (_head - 1) & (_table.length - 1); _table[_head] = value; if (_head == _tail) _grow(); _modificationCount++; } E removeFirst() { if (_head == _tail) throw IterableElementError.noElement(); _modificationCount++; E result = _table[_head] as E; _table[_head] = null; _head = (_head + 1) & (_table.length - 1); return result; } E removeLast() { if (_head == _tail) throw IterableElementError.noElement(); _modificationCount++; _tail = (_tail - 1) & (_table.length - 1); E result = _table[_tail] as E; _table[_tail] = null; return result; } // Internal helper functions. /// Whether [number] is a power of two. /// /// Only works for positive numbers. static bool _isPowerOf2(int number) => (number & (number - 1)) == 0; /// Rounds [number] up to the nearest power of 2. /// /// If [number] is a power of 2 already, it is returned. /// /// Only works for positive numbers. static int _nextPowerOf2(int number) { assert(number > 0); number = (number << 1) - 1; for (;;) { int nextNumber = number & (number - 1); if (nextNumber == 0) return number; number = nextNumber; } } /// Check if the queue has been modified during iteration. void _checkModification(int expectedModificationCount) { if (expectedModificationCount != _modificationCount) { throw ConcurrentModificationError(this); } } /// Adds element at end of queue. Used by both [add] and [addAll]. void _add(E element) { _table[_tail] = element; _tail = (_tail + 1) & (_table.length - 1); if (_head == _tail) _grow(); _modificationCount++; } /// Removes the element at [offset] into [_table]. /// /// 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 /// offset or the following offset depending on how elements are moved /// to fill the hole. int _remove(int offset) { int mask = _table.length - 1; int startDistance = (offset - _head) & mask; int endDistance = (_tail - offset) & mask; if (startDistance < endDistance) { // Closest to start. int i = offset; while (i != _head) { int prevOffset = (i - 1) & mask; _table[i] = _table[prevOffset]; i = prevOffset; } _table[_head] = null; _head = (_head + 1) & mask; return (offset + 1) & mask; } else { _tail = (_tail - 1) & mask; int i = offset; while (i != _tail) { int nextOffset = (i + 1) & mask; _table[i] = _table[nextOffset]; i = nextOffset; } _table[_tail] = null; return offset; } } /// Grow the table when full. void _grow() { List newTable = List.filled(_table.length * 2, null); int split = _table.length - _head; newTable.setRange(0, split, _table, _head); newTable.setRange(split, split + _head, _table, 0); _head = 0; _tail = _table.length; _table = newTable; } int _writeToList(List target) { assert(target.length >= length); if (_head <= _tail) { int length = _tail - _head; target.setRange(0, length, _table, _head); return length; } else { int firstPartSize = _table.length - _head; target.setRange(0, firstPartSize, _table, _head); target.setRange(firstPartSize, firstPartSize + _tail, _table, 0); return _tail + firstPartSize; } } /// Grows the table even if it is not full. void _preGrow(int newElementCount) { assert(newElementCount >= length); // Add some extra room to ensure that there's room for more elements after // expansion. newElementCount += newElementCount >> 1; int newCapacity = _nextPowerOf2(newElementCount); List newTable = List.filled(newCapacity, null); _tail = _writeToList(newTable); _table = newTable; _head = 0; } } /// Iterator for a [ListQueue]. /// /// Considers any add or remove operation a concurrent modification. class _ListQueueIterator implements Iterator { final ListQueue _queue; final int _end; final int _modificationCount; int _position; E? _current; _ListQueueIterator(ListQueue queue) : _queue = queue, _end = queue._tail, _modificationCount = queue._modificationCount, _position = queue._head; E get current => _current as E; bool moveNext() { _queue._checkModification(_modificationCount); if (_position == _end) { _current = null; return false; } _current = _queue._table[_position]; _position = (_position + 1) & (_queue._table.length - 1); return true; } }