2019-09-10 19:20:12 +00:00
|
|
|
// 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> {
|
2019-11-05 19:21:23 +00:00
|
|
|
T get first => _first as T;
|
|
|
|
T? _first;
|
|
|
|
|
|
|
|
T get last => _last as T;
|
|
|
|
T? _last;
|
|
|
|
|
2019-09-10 19:20:12 +00:00
|
|
|
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);
|
2019-11-05 19:21:23 +00:00
|
|
|
if (_last != null) {
|
|
|
|
assert(_last!._next == null);
|
|
|
|
_last!._next = newLast;
|
2019-09-10 19:20:12 +00:00
|
|
|
} else {
|
2019-11-05 19:21:23 +00:00
|
|
|
_first = newLast;
|
2019-09-10 19:20:12 +00:00
|
|
|
}
|
2019-11-05 19:21:23 +00:00
|
|
|
newLast._previous = _last;
|
|
|
|
_last = newLast;
|
|
|
|
_last!._list = this;
|
2019-09-10 19:20:12 +00:00
|
|
|
length++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds [newFirst] to the beginning of this linked list.
|
|
|
|
*/
|
|
|
|
void addFirst(T newFirst) {
|
2019-11-05 19:21:23 +00:00
|
|
|
if (_first != null) {
|
|
|
|
assert(_first!._previous == null);
|
|
|
|
_first!._previous = newFirst;
|
2019-09-10 19:20:12 +00:00
|
|
|
} else {
|
2019-11-05 19:21:23 +00:00
|
|
|
_last = newFirst;
|
2019-09-10 19:20:12 +00:00
|
|
|
}
|
2019-11-05 19:21:23 +00:00
|
|
|
newFirst._next = _first;
|
|
|
|
_first = newFirst;
|
|
|
|
_first!._list = this;
|
2019-09-10 19:20:12 +00:00
|
|
|
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) {
|
2019-11-05 19:21:23 +00:00
|
|
|
assert(identical(node, _first));
|
|
|
|
_first = node._next;
|
2019-09-10 19:20:12 +00:00
|
|
|
} else {
|
2019-11-05 19:21:23 +00:00
|
|
|
node._previous!._next = node._next;
|
2019-09-10 19:20:12 +00:00
|
|
|
}
|
|
|
|
if (node._next == null) {
|
2019-11-05 19:21:23 +00:00
|
|
|
assert(identical(node, _last));
|
|
|
|
_last = node._previous;
|
2019-09-10 19:20:12 +00:00
|
|
|
} else {
|
2019-11-05 19:21:23 +00:00
|
|
|
node._next!._previous = node._previous;
|
2019-09-10 19:20:12 +00:00
|
|
|
}
|
|
|
|
node._next = node._previous = null;
|
|
|
|
node._list = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
Iterator<T> get iterator => new _LinkedListIterator<T>(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
class LinkedListEntry<T extends LinkedListEntry<T>> {
|
2019-11-05 19:21:23 +00:00
|
|
|
T? _next;
|
|
|
|
T? _previous;
|
|
|
|
LinkedList<T>? _list;
|
2019-09-10 19:20:12 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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() {
|
2019-11-05 19:21:23 +00:00
|
|
|
_list?.remove(this as T);
|
2019-09-10 19:20:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class _LinkedListIterator<T extends LinkedListEntry<T>> implements Iterator<T> {
|
|
|
|
/// The current element of the iterator.
|
2019-11-05 19:21:23 +00:00
|
|
|
T? _current;
|
2020-03-04 21:07:16 +00:00
|
|
|
|
|
|
|
T get current {
|
|
|
|
final cur = _current;
|
|
|
|
return (cur != null) ? cur : cur as T;
|
|
|
|
}
|
2019-09-10 19:20:12 +00:00
|
|
|
|
|
|
|
/// 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.
|
2019-11-05 19:21:23 +00:00
|
|
|
LinkedList<T>? _list;
|
2019-09-10 19:20:12 +00:00
|
|
|
|
2019-11-05 19:21:23 +00:00
|
|
|
_LinkedListIterator(LinkedList<T> list) : _list = list {
|
|
|
|
if (list.length == 0) _list = null;
|
2019-09-10 19:20:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
2019-11-05 19:21:23 +00:00
|
|
|
if (_current == null) {
|
|
|
|
var list = _list;
|
|
|
|
if (list == null) return false;
|
|
|
|
assert(list.length > 0);
|
|
|
|
_current = list.first;
|
2019-09-10 19:20:12 +00:00
|
|
|
_list = null;
|
|
|
|
return true;
|
|
|
|
}
|
2019-11-05 19:21:23 +00:00
|
|
|
_current = _current!._next;
|
|
|
|
return _current != null;
|
2019-09-10 19:20:12 +00:00
|
|
|
}
|
|
|
|
}
|