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; |
+ } |
+} |