| // Copyright (c) 2017, 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._internal; |
| |
| /// A rudimentary linked list. |
| class LinkedList<T extends LinkedListEntry<T>> extends IterableBase<T> { |
| T get first => _first as T; |
| T? _first; |
| |
| T get last => _last as T; |
| T? _last; |
| |
| int length = 0; |
| |
| bool get isEmpty => length == 0; |
| |
| /** |
| * Adds [newLast] to the end of this linked list. |
| */ |
| void add(T newLast) { |
| assert(newLast._next == null && newLast._previous == null); |
| if (_last != null) { |
| assert(_last!._next == null); |
| _last!._next = newLast; |
| } else { |
| _first = newLast; |
| } |
| newLast._previous = _last; |
| _last = newLast; |
| _last!._list = this; |
| length++; |
| } |
| |
| /** |
| * Adds [newFirst] to the beginning of this linked list. |
| */ |
| void addFirst(T newFirst) { |
| if (_first != null) { |
| assert(_first!._previous == null); |
| _first!._previous = newFirst; |
| } else { |
| _last = newFirst; |
| } |
| newFirst._next = _first; |
| _first = newFirst; |
| _first!._list = this; |
| length++; |
| } |
| |
| /** |
| * Removes the given [node] from this list. |
| * |
| * If the entry is not in this linked list nothing happens. |
| * |
| * Also see [LinkedListEntry.unlink]. |
| */ |
| void remove(T node) { |
| if (node._list != this) return; |
| length--; |
| if (node._previous == null) { |
| assert(identical(node, _first)); |
| _first = node._next; |
| } else { |
| node._previous!._next = node._next; |
| } |
| if (node._next == null) { |
| assert(identical(node, _last)); |
| _last = node._previous; |
| } else { |
| node._next!._previous = node._previous; |
| } |
| node._next = node._previous = null; |
| node._list = null; |
| } |
| |
| Iterator<T> get iterator => new _LinkedListIterator<T>(this); |
| } |
| |
| class LinkedListEntry<T extends LinkedListEntry<T>> { |
| T? _next; |
| T? _previous; |
| LinkedList<T>? _list; |
| |
| /** |
| * Unlinks the element from its linked list. |
| * |
| * If the entry is not in a linked list, does nothing. Otherwise, this |
| * is equivalent to calling [LinkedList.remove] on the list this entry |
| * is currently in. |
| */ |
| void unlink() { |
| _list?.remove(this as T); |
| } |
| } |
| |
| class _LinkedListIterator<T extends LinkedListEntry<T>> implements Iterator<T> { |
| /// The current element of the iterator. |
| T? _current; |
| |
| T get current => _current as T; |
| |
| /// The list the iterator iterates over. |
| /// |
| /// Set to [null] if the provided list was empty (indicating that there were |
| /// no entries to iterate over). |
| /// |
| /// Set to [null] as soon as [moveNext] was invoked (indicating that the |
| /// iterator has to work with [current] from now on. |
| LinkedList<T>? _list; |
| |
| _LinkedListIterator(LinkedList<T> list) : _list = list { |
| if (list.length == 0) _list = null; |
| } |
| |
| bool moveNext() { |
| // current is null if the iterator hasn't started iterating, or if the |
| // iteration is finished. In the first case, the [_list] field is not null. |
| if (_current == null) { |
| var list = _list; |
| if (list == null) return false; |
| assert(list.length > 0); |
| _current = list.first; |
| _list = null; |
| return true; |
| } |
| _current = _current!._next; |
| return _current != null; |
| } |
| } |