OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 part of dart.collection; | |
6 | |
7 | |
8 /** | |
9 * A specialized double-linked list of elements that extends [LinkedListEntry]. | |
10 * | |
11 * This is not a generic data structure. It only accepts elements that extend | |
12 * the [LinkedListEntry] class. See the [Queue] implementations for | |
13 * generic collections that allow constant time adding and removing at the ends. | |
14 * | |
15 * 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 | |
17 * index. | |
18 * | |
19 * 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 | |
21 * list, it must first be removed from its current list (if any). | |
22 * | |
23 * 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], | |
25 * [LinkedListEntry.addBefore] and [LinkedListEntry.unlink] operations | |
26 * when all you have is the element. | |
27 * | |
28 * A `LinkedList` also allows constant time adding and removing at either end, | |
29 * and a constant time length getter. | |
30 */ | |
31 class LinkedList<E extends LinkedListEntry<E>> | |
32 extends Iterable<E> { | |
33 | |
34 int _modificationCount = 0; | |
35 int _length = 0; | |
36 E _first; | |
37 | |
38 /** | |
39 * Construct a new empty linked list. | |
40 */ | |
41 LinkedList(); | |
42 | |
43 /** | |
44 * Add [entry] to the beginning of the linked list. | |
45 */ | |
46 void addFirst(E entry) { | |
47 _insertBefore(_first, entry, updateFirst: true); | |
48 _first = entry; | |
49 } | |
50 | |
51 /** | |
52 * Add [entry] to the end of the linked list. | |
53 */ | |
54 void add(E entry) { | |
55 _insertBefore(_first, entry, updateFirst: false); | |
56 } | |
57 | |
58 /** | |
59 * Add [entries] to the end of the linked list. | |
60 */ | |
61 void addAll(Iterable<E> entries) { | |
62 entries.forEach(add); | |
63 } | |
64 | |
65 /** | |
66 * Remove [entry] from the linked list. | |
67 * | |
68 * Returns false and does nothing if [entry] is not in this linked list. | |
69 * | |
70 * This is equivalent to calling `entry.unlink()` if the entry is in this | |
71 * list. | |
72 */ | |
73 bool remove(E entry) { | |
74 if (entry._list != this) return false; | |
75 _unlink(entry); // Unlink will decrement length. | |
76 return true; | |
77 } | |
78 | |
79 Iterator<E> get iterator => new _LinkedListIterator<E>(this); | |
80 | |
81 int get length => _length; | |
82 | |
83 /** | |
84 * Remove all elements from this linked list. | |
85 */ | |
86 void clear() { | |
87 _modificationCount++; | |
88 if (isEmpty) return; | |
89 | |
90 E next = _first; | |
91 do { | |
92 E entry = next; | |
93 next = entry._next; | |
94 entry._next = entry._previous = entry._list = null; | |
95 } while (!identical(next, _first)); | |
96 | |
97 _first = null; | |
98 _length = 0; | |
99 } | |
100 | |
101 E get first { | |
102 if (isEmpty) { | |
103 throw new StateError('No such element'); | |
104 } | |
105 return _first; | |
106 } | |
107 | |
108 E get last { | |
109 if (isEmpty) { | |
110 throw new StateError('No such element'); | |
111 } | |
112 return _first._previous; | |
113 } | |
114 | |
115 E get single { | |
116 if (isEmpty) { | |
117 throw new StateError('No such element'); | |
118 } | |
119 if (_length > 1) { | |
120 throw new StateError('Too many elements'); | |
121 } | |
122 return _first; | |
123 } | |
124 | |
125 /** | |
126 * Call [action] with each entry in this linked list. | |
127 * | |
128 * It's an error if [action] modify the linked list. | |
129 */ | |
130 void forEach(void action(E entry)) { | |
131 int modificationCount = _modificationCount; | |
132 if (isEmpty) return; | |
133 | |
134 E current = _first; | |
135 do { | |
136 action(current); | |
137 if (modificationCount != _modificationCount) { | |
138 throw new ConcurrentModificationError(this); | |
139 } | |
140 current = current._next; | |
141 } while (!identical(current, _first)); | |
142 } | |
143 | |
144 bool get isEmpty => _length == 0; | |
145 | |
146 /// Inserts [newEntry] as last entry of the list. | |
147 /// | |
148 /// 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. | |
150 void _insertBefore(E entry, E newEntry, {bool updateFirst}) { | |
151 if (newEntry.list != null) { | |
152 throw new StateError( | |
153 'LinkedListEntry is already in a LinkedList'); | |
154 } | |
155 _modificationCount++; | |
156 | |
157 newEntry._list = this; | |
158 if (isEmpty) { | |
159 assert(entry == null); | |
160 newEntry._previous = newEntry._next = newEntry; | |
161 _first = newEntry; | |
162 _length++; | |
163 return; | |
164 } | |
165 E predecessor = entry._previous; | |
166 E successor = entry; | |
167 newEntry._previous = predecessor; | |
168 newEntry._next = successor; | |
169 predecessor._next = newEntry; | |
170 successor._previous = newEntry; | |
171 if (updateFirst && identical(entry, _first)) { | |
172 _first = newEntry; | |
173 } | |
174 _length++; | |
175 } | |
176 | |
177 void _unlink(E entry) { | |
178 _modificationCount++; | |
179 entry._next._previous = entry._previous; | |
180 E next = entry._previous._next = entry._next; | |
181 _length--; | |
182 entry._list = entry._next = entry._previous = null; | |
183 if (isEmpty) { | |
184 _first = null; | |
185 } else if (identical(entry, _first)) { | |
186 _first = next; | |
187 } | |
188 } | |
189 } | |
190 | |
191 | |
192 class _LinkedListIterator<E extends LinkedListEntry<E>> | |
193 implements Iterator<E> { | |
194 final LinkedList<E> _list; | |
195 final int _modificationCount; | |
196 E _current; | |
197 LinkedListEntry<E> _next; | |
198 bool _visitedFirst; | |
199 | |
200 _LinkedListIterator(LinkedList<E> list) | |
201 : _list = list, | |
202 _modificationCount = list._modificationCount, | |
203 _next = list._first, | |
204 _visitedFirst = false; | |
205 | |
206 E get current => _current; | |
207 | |
208 bool moveNext() { | |
209 if (_modificationCount != _list._modificationCount) { | |
210 throw new ConcurrentModificationError(this); | |
211 } | |
212 if (_list.isEmpty || | |
213 (_visitedFirst && identical(_next, _list.first))) { | |
214 _current = null; | |
215 return false; | |
216 } | |
217 _visitedFirst = true; | |
218 _current = _next; | |
219 _next = _next._next; | |
220 return true; | |
221 } | |
222 } | |
223 | |
224 | |
225 /** | |
226 * An object that can be an element in a [LinkedList]. | |
227 * | |
228 * All elements of a `LinkedList` must extend this class. | |
229 * The class provides the internal links that link elements together | |
230 * in the `LinkedList`, and a reference to the linked list itself | |
231 * that an element is currently part of. | |
232 * | |
233 * 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 | |
235 * linked list, and otherwise the `list` property is `null`. | |
236 * | |
237 * When created, an entry is not in any linked list. | |
238 */ | |
239 abstract class LinkedListEntry<E extends LinkedListEntry<E>> { | |
240 LinkedList<E> _list; | |
241 E _next; | |
242 E _previous; | |
243 | |
244 /** | |
245 * Get the linked list containing this element. | |
246 * | |
247 * Returns `null` if this entry is not currently in any list. | |
248 */ | |
249 LinkedList<E> get list => _list; | |
250 | |
251 /** | |
252 * Unlink the element from its linked list. | |
253 * | |
254 * The entry must currently be in a linked list when this method is called. | |
255 */ | |
256 void unlink() { | |
257 _list._unlink(this); | |
258 } | |
259 | |
260 /** | |
261 * Return the succeessor of this element in its linked list. | |
262 * | |
263 * Returns `null` if there is no successor in the linked list, or if this | |
264 * entry is not currently in any list. | |
265 */ | |
266 E get next { | |
267 if (identical(this, _next)) return null; | |
268 return _next; | |
269 } | |
270 | |
271 /** | |
272 * Return the predecessor of this element in its linked list. | |
273 * | |
274 * Returns `null` if there is no predecessor in the linked list, or if this | |
275 * entry is not currently in any list. | |
276 */ | |
277 E get previous { | |
278 if (identical(this, _previous)) return null; | |
279 return _previous; | |
280 } | |
281 | |
282 /** | |
283 * Insert an element after this element in this element's linked list. | |
284 * | |
285 * This entry must be in a linked list when this method is called. | |
286 * The [entry] must not be in a linked list. | |
287 */ | |
288 void insertAfter(E entry) { | |
289 _list._insertBefore(_next, entry, updateFirst: false); | |
290 } | |
291 | |
292 /** | |
293 * Insert an element before this element in this element's linked list. | |
294 * | |
295 * This entry must be in a linked list when this method is called. | |
296 * The [entry] must not be in a linked list. | |
297 */ | |
298 void insertBefore(E entry) { | |
299 _list._insertBefore(this as dynamic/*=E*/, entry, updateFirst: true); | |
300 } | |
301 } | |
OLD | NEW |