Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(60)

Side by Side Diff: sdk/lib/collection/linked_list.dart

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

Powered by Google App Engine
This is Rietveld 408576698