OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart.collection; | 5 part of dart.collection; |
6 | 6 |
7 | |
8 /** | 7 /** |
9 * A specialized double-linked list of elements that extends [LinkedListEntry]. | 8 * A specialized double-linked list of elements that extends [LinkedListEntry]. |
10 * | 9 * |
11 * This is not a generic data structure. It only accepts elements that extend | 10 * This is not a generic data structure. It only accepts elements that extend |
12 * the [LinkedListEntry] class. See the [Queue] implementations for | 11 * the [LinkedListEntry] class. See the [Queue] implementations for |
13 * generic collections that allow constant time adding and removing at the ends. | 12 * generic collections that allow constant time adding and removing at the ends. |
14 * | 13 * |
15 * This is not a [List] implementation. Despite its name, this class does not | 14 * This is not a [List] implementation. Despite its name, this class does not |
16 * implement the [List] interface. It does not allow constant time lookup by | 15 * implement the [List] interface. It does not allow constant time lookup by |
17 * index. | 16 * index. |
18 * | 17 * |
19 * Because the elements themselves contain the links of this linked list, | 18 * Because the elements themselves contain the links of this linked list, |
20 * each element can be in only one list at a time. To add an element to another | 19 * each element can be in only one list at a time. To add an element to another |
21 * list, it must first be removed from its current list (if any). | 20 * list, it must first be removed from its current list (if any). |
22 * | 21 * |
23 * In return, each element knows its own place in the linked list, as well as | 22 * In return, each element knows its own place in the linked list, as well as |
24 * which list it is in. This allows constant time [LinkedListEntry.addAfter], | 23 * which list it is in. This allows constant time [LinkedListEntry.addAfter], |
25 * [LinkedListEntry.addBefore] and [LinkedListEntry.unlink] operations | 24 * [LinkedListEntry.addBefore] and [LinkedListEntry.unlink] operations |
26 * when all you have is the element. | 25 * when all you have is the element. |
27 * | 26 * |
28 * A `LinkedList` also allows constant time adding and removing at either end, | 27 * A `LinkedList` also allows constant time adding and removing at either end, |
29 * and a constant time length getter. | 28 * and a constant time length getter. |
30 */ | 29 */ |
31 class LinkedList<E extends LinkedListEntry<E>> | 30 class LinkedList<E extends LinkedListEntry<E>> extends Iterable<E> { |
32 extends Iterable<E> { | |
33 | |
34 int _modificationCount = 0; | 31 int _modificationCount = 0; |
35 int _length = 0; | 32 int _length = 0; |
36 E _first; | 33 E _first; |
37 | 34 |
38 /** | 35 /** |
39 * Construct a new empty linked list. | 36 * Construct a new empty linked list. |
40 */ | 37 */ |
41 LinkedList(); | 38 LinkedList(); |
42 | 39 |
43 /** | 40 /** |
(...skipping 21 matching lines...) Expand all Loading... |
65 /** | 62 /** |
66 * Remove [entry] from the linked list. | 63 * Remove [entry] from the linked list. |
67 * | 64 * |
68 * Returns false and does nothing if [entry] is not in this linked list. | 65 * Returns false and does nothing if [entry] is not in this linked list. |
69 * | 66 * |
70 * This is equivalent to calling `entry.unlink()` if the entry is in this | 67 * This is equivalent to calling `entry.unlink()` if the entry is in this |
71 * list. | 68 * list. |
72 */ | 69 */ |
73 bool remove(E entry) { | 70 bool remove(E entry) { |
74 if (entry._list != this) return false; | 71 if (entry._list != this) return false; |
75 _unlink(entry); // Unlink will decrement length. | 72 _unlink(entry); // Unlink will decrement length. |
76 return true; | 73 return true; |
77 } | 74 } |
78 | 75 |
79 Iterator<E> get iterator => new _LinkedListIterator<E>(this); | 76 Iterator<E> get iterator => new _LinkedListIterator<E>(this); |
80 | 77 |
81 int get length => _length; | 78 int get length => _length; |
82 | 79 |
83 /** | 80 /** |
84 * Remove all elements from this linked list. | 81 * Remove all elements from this linked list. |
85 */ | 82 */ |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 } | 139 } |
143 | 140 |
144 bool get isEmpty => _length == 0; | 141 bool get isEmpty => _length == 0; |
145 | 142 |
146 /// Inserts [newEntry] as last entry of the list. | 143 /// Inserts [newEntry] as last entry of the list. |
147 /// | 144 /// |
148 /// If [updateFirst] is true and [entry] is the first entry in the list, | 145 /// If [updateFirst] is true and [entry] is the first entry in the list, |
149 /// updates the [_first] field to point to the [newEntry] as first entry. | 146 /// updates the [_first] field to point to the [newEntry] as first entry. |
150 void _insertBefore(E entry, E newEntry, {bool updateFirst}) { | 147 void _insertBefore(E entry, E newEntry, {bool updateFirst}) { |
151 if (newEntry.list != null) { | 148 if (newEntry.list != null) { |
152 throw new StateError( | 149 throw new StateError('LinkedListEntry is already in a LinkedList'); |
153 'LinkedListEntry is already in a LinkedList'); | |
154 } | 150 } |
155 _modificationCount++; | 151 _modificationCount++; |
156 | 152 |
157 newEntry._list = this; | 153 newEntry._list = this; |
158 if (isEmpty) { | 154 if (isEmpty) { |
159 assert(entry == null); | 155 assert(entry == null); |
160 newEntry._previous = newEntry._next = newEntry; | 156 newEntry._previous = newEntry._next = newEntry; |
161 _first = newEntry; | 157 _first = newEntry; |
162 _length++; | 158 _length++; |
163 return; | 159 return; |
(...skipping 17 matching lines...) Expand all Loading... |
181 _length--; | 177 _length--; |
182 entry._list = entry._next = entry._previous = null; | 178 entry._list = entry._next = entry._previous = null; |
183 if (isEmpty) { | 179 if (isEmpty) { |
184 _first = null; | 180 _first = null; |
185 } else if (identical(entry, _first)) { | 181 } else if (identical(entry, _first)) { |
186 _first = next; | 182 _first = next; |
187 } | 183 } |
188 } | 184 } |
189 } | 185 } |
190 | 186 |
191 | 187 class _LinkedListIterator<E extends LinkedListEntry<E>> implements Iterator<E> { |
192 class _LinkedListIterator<E extends LinkedListEntry<E>> | |
193 implements Iterator<E> { | |
194 final LinkedList<E> _list; | 188 final LinkedList<E> _list; |
195 final int _modificationCount; | 189 final int _modificationCount; |
196 E _current; | 190 E _current; |
197 LinkedListEntry<E> _next; | 191 LinkedListEntry<E> _next; |
198 bool _visitedFirst; | 192 bool _visitedFirst; |
199 | 193 |
200 _LinkedListIterator(LinkedList<E> list) | 194 _LinkedListIterator(LinkedList<E> list) |
201 : _list = list, | 195 : _list = list, |
202 _modificationCount = list._modificationCount, | 196 _modificationCount = list._modificationCount, |
203 _next = list._first, | 197 _next = list._first, |
204 _visitedFirst = false; | 198 _visitedFirst = false; |
205 | 199 |
206 E get current => _current; | 200 E get current => _current; |
207 | 201 |
208 bool moveNext() { | 202 bool moveNext() { |
209 if (_modificationCount != _list._modificationCount) { | 203 if (_modificationCount != _list._modificationCount) { |
210 throw new ConcurrentModificationError(this); | 204 throw new ConcurrentModificationError(this); |
211 } | 205 } |
212 if (_list.isEmpty || | 206 if (_list.isEmpty || (_visitedFirst && identical(_next, _list.first))) { |
213 (_visitedFirst && identical(_next, _list.first))) { | |
214 _current = null; | 207 _current = null; |
215 return false; | 208 return false; |
216 } | 209 } |
217 _visitedFirst = true; | 210 _visitedFirst = true; |
218 _current = _next; | 211 _current = _next; |
219 _next = _next._next; | 212 _next = _next._next; |
220 return true; | 213 return true; |
221 } | 214 } |
222 } | 215 } |
223 | 216 |
224 | |
225 /** | 217 /** |
226 * An object that can be an element in a [LinkedList]. | 218 * An object that can be an element in a [LinkedList]. |
227 * | 219 * |
228 * All elements of a `LinkedList` must extend this class. | 220 * All elements of a `LinkedList` must extend this class. |
229 * The class provides the internal links that link elements together | 221 * The class provides the internal links that link elements together |
230 * in the `LinkedList`, and a reference to the linked list itself | 222 * in the `LinkedList`, and a reference to the linked list itself |
231 * that an element is currently part of. | 223 * that an element is currently part of. |
232 * | 224 * |
233 * An entry can be in at most one linked list at a time. | 225 * An entry can be in at most one linked list at a time. |
234 * While an entry is in a linked list, the [list] property points to that | 226 * While an entry is in a linked list, the [list] property points to that |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 /** | 284 /** |
293 * Insert an element before this element in this element's linked list. | 285 * Insert an element before this element in this element's linked list. |
294 * | 286 * |
295 * This entry must be in a linked list when this method is called. | 287 * This entry must be in a linked list when this method is called. |
296 * The [entry] must not be in a linked list. | 288 * The [entry] must not be in a linked list. |
297 */ | 289 */ |
298 void insertBefore(E entry) { | 290 void insertBefore(E entry) { |
299 _list._insertBefore(this as dynamic/*=E*/, entry, updateFirst: true); | 291 _list._insertBefore(this as dynamic/*=E*/, entry, updateFirst: true); |
300 } | 292 } |
301 } | 293 } |
OLD | NEW |