| Index: sdk/lib/internal/linked_list.dart
|
| diff --git a/sdk/lib/internal/linked_list.dart b/sdk/lib/internal/linked_list.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..31a6c01cab8b5666840de4d04e7088f2395b18ef
|
| --- /dev/null
|
| +++ b/sdk/lib/internal/linked_list.dart
|
| @@ -0,0 +1,126 @@
|
| +// 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 first;
|
| + 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() {
|
| + if (_list == null) return;
|
| + _list.remove(this);
|
| + }
|
| +}
|
| +
|
| +class _LinkedListIterator<T extends LinkedListEntry<T>> implements Iterator<T> {
|
| + /// The current element of the iterator.
|
| + // This field is writeable, but should only read by users of this class.
|
| + T current;
|
| +
|
| + /// 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(this._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) {
|
| + if (_list == null) return false;
|
| + assert(_list.length > 0);
|
| + current = _list.first;
|
| + _list = null;
|
| + return true;
|
| + }
|
| + current = current._next;
|
| + return current != null;
|
| + }
|
| +}
|
|
|