Index: sdk/lib/collection/linked_list.dart |
diff --git a/sdk/lib/collection/linked_list.dart b/sdk/lib/collection/linked_list.dart |
index e2139c012d2720dc452c43e4c0100222c5b80156..481f04dde02fd599b8d9ac36d131cb1e360c221b 100644 |
--- a/sdk/lib/collection/linked_list.dart |
+++ b/sdk/lib/collection/linked_list.dart |
@@ -29,40 +29,37 @@ part of dart.collection; |
* and a constant time length getter. |
*/ |
class LinkedList<E extends LinkedListEntry<E>> |
- extends Iterable<E> |
- implements _LinkedListLink { |
+ extends Iterable<E> { |
int _modificationCount = 0; |
int _length = 0; |
- _LinkedListLink _next; |
- _LinkedListLink _previous; |
+ E _first; |
/** |
* Construct a new empty linked list. |
*/ |
- LinkedList() { |
- _next = _previous = this; |
- } |
+ LinkedList(); |
/** |
* Add [entry] to the beginning of the linked list. |
*/ |
void addFirst(E entry) { |
- _insertAfter(this, entry); |
+ _insertBefore(_first, entry, updateFirst: true); |
+ _first = entry; |
} |
/** |
* Add [entry] to the end of the linked list. |
*/ |
void add(E entry) { |
- _insertAfter(_previous, entry); |
+ _insertBefore(_first, entry, updateFirst: false); |
} |
/** |
* Add [entries] to the end of the linked list. |
*/ |
void addAll(Iterable<E> entries) { |
- entries.forEach((entry) => _insertAfter(_previous, entry)); |
+ entries.forEach(add); |
} |
/** |
@@ -88,38 +85,41 @@ class LinkedList<E extends LinkedListEntry<E>> |
*/ |
void clear() { |
_modificationCount++; |
- _LinkedListLink next = _next; |
- while (!identical(next, this)) { |
+ if (isEmpty) return; |
+ |
+ E next = _first; |
+ do { |
E entry = next; |
next = entry._next; |
entry._next = entry._previous = entry._list = null; |
- } |
- _next = _previous = this; |
+ } while (!identical(next, _first)); |
+ |
+ _first = null; |
_length = 0; |
} |
E get first { |
- if (identical(_next, this)) { |
+ if (isEmpty) { |
throw new StateError('No such element'); |
} |
- return _next; |
+ return _first; |
} |
E get last { |
- if (identical(_previous, this)) { |
+ if (isEmpty) { |
throw new StateError('No such element'); |
} |
- return _previous; |
+ return _first._previous; |
} |
E get single { |
- if (identical(_previous, this)) { |
+ if (isEmpty) { |
throw new StateError('No such element'); |
} |
- if (!identical(_previous, _next)) { |
+ if (_length > 1) { |
throw new StateError('Too many elements'); |
} |
- return _next; |
+ return _first; |
} |
/** |
@@ -129,40 +129,62 @@ class LinkedList<E extends LinkedListEntry<E>> |
*/ |
void forEach(void action(E entry)) { |
int modificationCount = _modificationCount; |
- _LinkedListLink current = _next; |
- while (!identical(current, this)) { |
+ if (isEmpty) return; |
+ |
+ E current = _first; |
+ do { |
action(current); |
if (modificationCount != _modificationCount) { |
throw new ConcurrentModificationError(this); |
} |
current = current._next; |
- } |
+ } while (!identical(current, _first)); |
} |
bool get isEmpty => _length == 0; |
- void _insertAfter(_LinkedListLink entry, E newEntry) { |
+ /// Inserts [newEntry] as last entry of the list. |
+ /// |
+ /// If [updateFirst] is true and [entry] is the first entry in the list, |
+ /// updates the [_first] field to point to the [newEntry] as first entry. |
+ void _insertBefore(E entry, E newEntry, {bool updateFirst}) { |
if (newEntry.list != null) { |
throw new StateError( |
'LinkedListEntry is already in a LinkedList'); |
} |
_modificationCount++; |
+ |
newEntry._list = this; |
- var predecessor = entry; |
- var successor = entry._next; |
- successor._previous = newEntry; |
+ if (isEmpty) { |
+ assert(entry == null); |
+ newEntry._previous = newEntry._next = newEntry; |
+ _first = newEntry; |
+ _length++; |
+ return; |
+ } |
+ E predecessor = entry._previous; |
+ E successor = entry; |
newEntry._previous = predecessor; |
newEntry._next = successor; |
predecessor._next = newEntry; |
+ successor._previous = newEntry; |
+ if (updateFirst && identical(entry, _first)) { |
+ _first = newEntry; |
+ } |
_length++; |
} |
- void _unlink(LinkedListEntry<E> entry) { |
+ void _unlink(E entry) { |
_modificationCount++; |
entry._next._previous = entry._previous; |
- entry._previous._next = entry._next; |
+ E next = entry._previous._next = entry._next; |
_length--; |
entry._list = entry._next = entry._previous = null; |
+ if (isEmpty) { |
+ _first = null; |
+ } else if (identical(entry, _first)) { |
+ _first = next; |
+ } |
} |
} |
@@ -172,23 +194,27 @@ class _LinkedListIterator<E extends LinkedListEntry<E>> |
final LinkedList<E> _list; |
final int _modificationCount; |
E _current; |
- _LinkedListLink _next; |
+ LinkedListEntry<E> _next; |
+ bool _visitedFirst; |
_LinkedListIterator(LinkedList<E> list) |
: _list = list, |
_modificationCount = list._modificationCount, |
- _next = list._next; |
+ _next = list._first, |
+ _visitedFirst = false; |
E get current => _current; |
bool moveNext() { |
- if (identical(_next, _list)) { |
- _current = null; |
- return false; |
- } |
if (_modificationCount != _list._modificationCount) { |
throw new ConcurrentModificationError(this); |
} |
+ if (_list.isEmpty || |
+ (_visitedFirst && identical(_next, _list.first))) { |
+ _current = null; |
+ return false; |
+ } |
+ _visitedFirst = true; |
_current = _next; |
_next = _next._next; |
return true; |
@@ -196,12 +222,6 @@ class _LinkedListIterator<E extends LinkedListEntry<E>> |
} |
-class _LinkedListLink { |
- _LinkedListLink _next; |
- _LinkedListLink _previous; |
-} |
- |
- |
/** |
* An object that can be an element in a [LinkedList]. |
* |
@@ -216,11 +236,10 @@ class _LinkedListLink { |
* |
* When created, an entry is not in any linked list. |
*/ |
-abstract class LinkedListEntry<E extends LinkedListEntry<E>> |
- implements _LinkedListLink { |
+abstract class LinkedListEntry<E extends LinkedListEntry<E>> { |
LinkedList<E> _list; |
- _LinkedListLink _next; |
- _LinkedListLink _previous; |
+ E _next; |
+ E _previous; |
/** |
* Get the linked list containing this element. |
@@ -245,9 +264,8 @@ abstract class LinkedListEntry<E extends LinkedListEntry<E>> |
* entry is not currently in any list. |
*/ |
E get next { |
- if (identical(_next, _list)) return null; |
- E result = _next; |
- return result; |
+ if (identical(this, _next)) return null; |
+ return _next; |
} |
/** |
@@ -257,8 +275,8 @@ abstract class LinkedListEntry<E extends LinkedListEntry<E>> |
* entry is not currently in any list. |
*/ |
E get previous { |
- if (identical(_previous, _list)) return null; |
- return _previous as E; |
+ if (identical(this, _previous)) return null; |
+ return _previous; |
} |
/** |
@@ -268,7 +286,7 @@ abstract class LinkedListEntry<E extends LinkedListEntry<E>> |
* The [entry] must not be in a linked list. |
*/ |
void insertAfter(E entry) { |
- _list._insertAfter(this, entry); |
+ _list._insertBefore(_next, entry, updateFirst: false); |
} |
/** |
@@ -278,6 +296,6 @@ abstract class LinkedListEntry<E extends LinkedListEntry<E>> |
* The [entry] must not be in a linked list. |
*/ |
void insertBefore(E entry) { |
- _list._insertAfter(_previous, entry); |
+ _list._insertBefore(this as dynamic/*=E*/, entry, updateFirst: true); |
} |
} |