|  | // Copyright (c) 2013, 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.collection; | 
|  |  | 
|  | /// A specialized double-linked list of elements that extends [LinkedListEntry]. | 
|  | /// | 
|  | /// This is not a generic data structure. It only accepts elements that extend | 
|  | /// the [LinkedListEntry] class. See the [Queue] implementations for generic | 
|  | /// collections that allow constant time adding and removing at the ends. | 
|  | /// | 
|  | /// This is not a [List] implementation. Despite its name, this class does not | 
|  | /// implement the [List] interface. It does not allow constant time lookup by | 
|  | /// index. | 
|  | /// | 
|  | /// Because the elements themselves contain the links of this linked list, | 
|  | /// each element can be in only one list at a time. To add an element to another | 
|  | /// list, it must first be removed from its current list (if any). | 
|  | /// | 
|  | /// In return, each element knows its own place in the linked list, as well as | 
|  | /// which list it is in. This allows constant time | 
|  | /// [LinkedListEntry.insertAfter], [LinkedListEntry.insertBefore] and | 
|  | /// [LinkedListEntry.unlink] operations when all you have is the element. | 
|  | /// | 
|  | /// A `LinkedList` also allows constant time adding and removing at either end, | 
|  | /// and a constant time length getter. | 
|  | class LinkedList<E extends LinkedListEntry<E>> extends Iterable<E> { | 
|  | int _modificationCount = 0; | 
|  | int _length = 0; | 
|  | E _first; | 
|  |  | 
|  | /// Construct a new empty linked list. | 
|  | LinkedList(); | 
|  |  | 
|  | /// Add [entry] to the beginning of the linked list. | 
|  | void addFirst(E entry) { | 
|  | _insertBefore(_first, entry, updateFirst: true); | 
|  | _first = entry; | 
|  | } | 
|  |  | 
|  | /// Add [entry] to the end of the linked list. | 
|  | void add(E entry) { | 
|  | _insertBefore(_first, entry, updateFirst: false); | 
|  | } | 
|  |  | 
|  | /// Add [entries] to the end of the linked list. | 
|  | void addAll(Iterable<E> entries) { | 
|  | entries.forEach(add); | 
|  | } | 
|  |  | 
|  | /// Remove [entry] from the linked list. | 
|  | /// | 
|  | /// Returns false and does nothing if [entry] is not in this linked list. | 
|  | /// | 
|  | /// This is equivalent to calling `entry.unlink()` if the entry is in this | 
|  | /// list. | 
|  | bool remove(E entry) { | 
|  | if (entry._list != this) return false; | 
|  | _unlink(entry); // Unlink will decrement length. | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Iterator<E> get iterator => _LinkedListIterator<E>(this); | 
|  |  | 
|  | int get length => _length; | 
|  |  | 
|  | /// Remove all elements from this linked list. | 
|  | void clear() { | 
|  | _modificationCount++; | 
|  | if (isEmpty) return; | 
|  |  | 
|  | E next = _first; | 
|  | do { | 
|  | E entry = next; | 
|  | next = entry._next; | 
|  | entry._next = entry._previous = entry._list = null; | 
|  | } while (!identical(next, _first)); | 
|  |  | 
|  | _first = null; | 
|  | _length = 0; | 
|  | } | 
|  |  | 
|  | E get first { | 
|  | if (isEmpty) { | 
|  | throw StateError('No such element'); | 
|  | } | 
|  | return _first; | 
|  | } | 
|  |  | 
|  | E get last { | 
|  | if (isEmpty) { | 
|  | throw StateError('No such element'); | 
|  | } | 
|  | return _first._previous; | 
|  | } | 
|  |  | 
|  | E get single { | 
|  | if (isEmpty) { | 
|  | throw StateError('No such element'); | 
|  | } | 
|  | if (_length > 1) { | 
|  | throw StateError('Too many elements'); | 
|  | } | 
|  | return _first; | 
|  | } | 
|  |  | 
|  | /// Call [action] with each entry in this linked list. | 
|  | /// | 
|  | /// It's an error if [action] modify the linked list. | 
|  | void forEach(void action(E entry)) { | 
|  | int modificationCount = _modificationCount; | 
|  | if (isEmpty) return; | 
|  |  | 
|  | E current = _first; | 
|  | do { | 
|  | action(current); | 
|  | if (modificationCount != _modificationCount) { | 
|  | throw ConcurrentModificationError(this); | 
|  | } | 
|  | current = current._next; | 
|  | } while (!identical(current, _first)); | 
|  | } | 
|  |  | 
|  | bool get isEmpty => _length == 0; | 
|  |  | 
|  | /// 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 StateError('LinkedListEntry is already in a LinkedList'); | 
|  | } | 
|  | _modificationCount++; | 
|  |  | 
|  | newEntry._list = this; | 
|  | 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(E entry) { | 
|  | _modificationCount++; | 
|  | entry._next._previous = entry._previous; | 
|  | 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; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | class _LinkedListIterator<E extends LinkedListEntry<E>> implements Iterator<E> { | 
|  | final LinkedList<E> _list; | 
|  | final int _modificationCount; | 
|  | E _current; | 
|  | LinkedListEntry<E> _next; | 
|  | bool _visitedFirst; | 
|  |  | 
|  | _LinkedListIterator(LinkedList<E> list) | 
|  | : _list = list, | 
|  | _modificationCount = list._modificationCount, | 
|  | _next = list._first, | 
|  | _visitedFirst = false; | 
|  |  | 
|  | E get current => _current; | 
|  |  | 
|  | bool moveNext() { | 
|  | if (_modificationCount != _list._modificationCount) { | 
|  | throw ConcurrentModificationError(this); | 
|  | } | 
|  | if (_list.isEmpty || (_visitedFirst && identical(_next, _list.first))) { | 
|  | _current = null; | 
|  | return false; | 
|  | } | 
|  | _visitedFirst = true; | 
|  | _current = _next; | 
|  | _next = _next._next; | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// An object that can be an element in a [LinkedList]. | 
|  | /// | 
|  | /// All elements of a `LinkedList` must extend this class. | 
|  | /// The class provides the internal links that link elements together | 
|  | /// in the `LinkedList`, and a reference to the linked list itself | 
|  | /// that an element is currently part of. | 
|  | /// | 
|  | /// An entry can be in at most one linked list at a time. | 
|  | /// While an entry is in a linked list, the [list] property points to that | 
|  | /// linked list, and otherwise the `list` property is `null`. | 
|  | /// | 
|  | /// When created, an entry is not in any linked list. | 
|  | abstract class LinkedListEntry<E extends LinkedListEntry<E>> { | 
|  | LinkedList<E> _list; | 
|  | E _next; | 
|  | E _previous; | 
|  |  | 
|  | /// Get the linked list containing this element. | 
|  | /// | 
|  | /// Returns `null` if this entry is not currently in any list. | 
|  | LinkedList<E> get list => _list; | 
|  |  | 
|  | /// Unlink the element from its linked list. | 
|  | /// | 
|  | /// The entry must currently be in a linked list when this method is called. | 
|  | void unlink() { | 
|  | _list._unlink(this); | 
|  | } | 
|  |  | 
|  | /// Return the successor of this element in its linked list. | 
|  | /// | 
|  | /// Returns `null` if there is no successor in the linked list, or if this | 
|  | /// entry is not currently in any list. | 
|  | E get next { | 
|  | if (_list == null || identical(_list.first, _next)) return null; | 
|  | return _next; | 
|  | } | 
|  |  | 
|  | /// Return the predecessor of this element in its linked list. | 
|  | /// | 
|  | /// Returns `null` if there is no predecessor in the linked list, or if this | 
|  | /// entry is not currently in any list. | 
|  | E get previous { | 
|  | if (_list == null || identical(this, _list.first)) return null; | 
|  | return _previous; | 
|  | } | 
|  |  | 
|  | /// Insert an element after this element in this element's linked list. | 
|  | /// | 
|  | /// This entry must be in a linked list when this method is called. | 
|  | /// The [entry] must not be in a linked list. | 
|  | void insertAfter(E entry) { | 
|  | _list._insertBefore(_next, entry, updateFirst: false); | 
|  | } | 
|  |  | 
|  | /// Insert an element before this element in this element's linked list. | 
|  | /// | 
|  | /// This entry must be in a linked list when this method is called. | 
|  | /// The [entry] must not be in a linked list. | 
|  | void insertBefore(E entry) { | 
|  | _list._insertBefore(this, entry, updateFirst: true); | 
|  | } | 
|  | } |