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.dev; | |
6 | |
7 /** | |
8 * Class implementing the read-operations on [List]. | |
9 * | |
10 * Implements all read-only operations, except [:operator[]:] and [:length:], | |
11 * in terms of those two operations. | |
12 */ | |
13 abstract class ListBase<E> extends Collection<E> implements List<E> { | |
14 Iterator<E> get iterator => new ListIterator(this); | |
15 | |
16 void forEach(f(E element)) { | |
17 for (int i = 0; i < this.length; i++) f(this[i]); | |
18 } | |
19 | |
20 bool contains(E value) { | |
21 for (int i = 0; i < length; i++) { | |
22 if (this[i] == value) return true; | |
23 } | |
24 return false; | |
25 } | |
26 | |
27 reduce(initialValue, combine(previousValue, E element)) { | |
28 var value = initialValue; | |
29 for (int i = 0; i < this.length; i++) { | |
30 value = combine(value, this[i]); | |
31 } | |
32 return value; | |
33 } | |
34 | |
35 bool every(bool f(E element)) { | |
36 for (int i = 0; i < this.length; i++) { | |
37 if (!f(this[i])) return false; | |
38 } | |
39 return true; | |
40 } | |
41 | |
42 bool any(bool f(E element)) { | |
43 for (int i = 0; i < this.length; i++) { | |
44 if (f(this[i])) return true; | |
45 } | |
46 return false; | |
47 } | |
48 | |
49 bool get isEmpty { | |
50 return this.length == 0; | |
51 } | |
52 | |
53 E elementAt(int index) { | |
54 return this[index]; | |
55 } | |
56 | |
57 int indexOf(E value, [int start = 0]) { | |
58 for (int i = start; i < length; i++) { | |
59 if (this[i] == value) return i; | |
60 } | |
61 return -1; | |
62 } | |
63 | |
64 int lastIndexOf(E value, [int start]) { | |
65 if (start == null) start = length - 1; | |
66 for (int i = start; i >= 0; i--) { | |
67 if (this[i] == value) return i; | |
68 } | |
69 return -1; | |
70 } | |
71 | |
72 E get first { | |
73 if (length > 0) return this[0]; | |
74 throw new StateError("No elements"); | |
75 } | |
76 | |
77 E get last { | |
78 if (length > 0) return this[length - 1]; | |
79 throw new StateError("No elements"); | |
80 } | |
81 | |
82 E get single { | |
83 if (length == 1) return this[0]; | |
84 if (length == 0) throw new StateError("No elements"); | |
85 throw new StateError("More than one element"); | |
86 } | |
87 | |
88 List<E> getRange(int start, int length) { | |
89 List<E> result = <E>[]; | |
90 for (int i = 0; i < length; i++) { | |
91 result.add(this[start + i]); | |
92 } | |
93 return result; | |
94 } | |
95 | |
96 Iterable map(f(E element)) { | |
97 return new MappedIterable(this, f); | |
98 } | |
99 | |
100 List mappedBy(f(E element)) { | |
101 return new MappedList(this, f); | |
102 } | |
103 | |
104 List<E> take(int n) { | |
105 return new ListView(this, 0, n); | |
106 } | |
107 | |
108 List<E> skip(int n) { | |
109 return new ListView(this, n, null); | |
110 } | |
111 | |
112 String toString() => ToString.collectionToString(this); | |
113 | |
114 List<E> get reversed { | |
115 return new ReversedListView(this, 0, null); | |
116 } | |
117 } | |
118 | |
119 /** | |
120 * Abstract class implementing the non-length changing operations of [List]. | |
121 */ | |
122 abstract class FixedLengthListBase<E> extends ListBase<E> { | |
123 void operator[]=(int index, E value); | |
124 | |
125 void sort([Comparator<E> compare]) { | |
126 Sort.sort(this, compare); | |
127 } | |
128 | |
129 void setRange(int start, int length, List<E> from, [int startFrom]) { | |
130 if (length < 0) throw new ArgumentError("length: $length"); | |
131 if (startFrom == null) startFrom = 0; | |
132 for (int i = 0; i < length; i++) { | |
133 this[start + i] = from[startFrom + i]; | |
134 } | |
135 } | |
136 | |
137 void set length(int newLength) { | |
138 throw new UnsupportedError( | |
139 "Cannot change the length of a fixed-length list"); | |
140 } | |
141 | |
142 void add(E value) { | |
143 throw new UnsupportedError( | |
144 "Cannot add to a fixed-length list"); | |
145 } | |
146 | |
147 void addLast(E value) { | |
148 throw new UnsupportedError( | |
149 "Cannot add to a fixed-length list"); | |
150 } | |
151 | |
152 void addAll(Iterable<E> iterable) { | |
153 throw new UnsupportedError( | |
154 "Cannot add to a fixed-length list"); | |
155 } | |
156 | |
157 void remove(E element) { | |
158 throw new UnsupportedError( | |
159 "Cannot remove from a fixed-length list"); | |
160 } | |
161 | |
162 void removeAll(Iterable elements) { | |
163 throw new UnsupportedError( | |
164 "Cannot remove from a fixed-length list"); | |
165 } | |
166 | |
167 void retainAll(Iterable elements) { | |
168 throw new UnsupportedError( | |
169 "Cannot remove from a fixed-length list"); | |
170 } | |
171 | |
172 void removeMatching(bool test(E element)) { | |
173 throw new UnsupportedError( | |
174 "Cannot remove from a fixed-length list"); | |
175 } | |
176 | |
177 void clear() { | |
178 throw new UnsupportedError( | |
179 "Cannot clear a fixed-length list"); | |
180 } | |
181 | |
182 E removeAt(int index) { | |
183 throw new UnsupportedError( | |
184 "Cannot remove from a fixed-length list"); | |
185 } | |
186 | |
187 E removeLast() { | |
188 throw new UnsupportedError( | |
189 "Cannot remove from a fixed-length list"); | |
190 } | |
191 | |
192 void removeRange(int start, int length) { | |
193 throw new UnsupportedError( | |
194 "Cannot remove from a fixed-length list"); | |
195 } | |
196 | |
197 void insertRange(int start, int length, [E initialValue]) { | |
198 throw new UnsupportedError( | |
199 "Cannot insert range in a fixed-length list"); | |
200 } | |
201 } | |
202 | |
203 /** | |
204 * An unmodifiable [List]. | |
205 */ | |
206 abstract class UnmodifiableListBase<E> extends ListBase<E> { | |
207 | |
208 void operator []=(int index, E value) { | |
209 throw new UnsupportedError( | |
210 "Cannot modify an unmodifiable list"); | |
211 } | |
212 | |
213 void set length(int newLength) { | |
214 throw new UnsupportedError( | |
215 "Cannot change the length of an unmodifiable list"); | |
216 } | |
217 | |
218 void add(E value) { | |
219 throw new UnsupportedError( | |
220 "Cannot add to an unmodifiable list"); | |
221 } | |
222 | |
223 void addLast(E value) { | |
224 throw new UnsupportedError( | |
225 "Cannot add to an unmodifiable list"); | |
226 } | |
227 | |
228 void addAll(Iterable<E> iterable) { | |
229 throw new UnsupportedError( | |
230 "Cannot add to an unmodifiable list"); | |
231 } | |
232 | |
233 void remove(E element) { | |
234 throw new UnsupportedError( | |
235 "Cannot remove from an unmodifiable list"); | |
236 } | |
237 | |
238 void removeAll(Iterable elements) { | |
239 throw new UnsupportedError( | |
240 "Cannot remove from an unmodifiable list"); | |
241 } | |
242 | |
243 void retainAll(Iterable elements) { | |
244 throw new UnsupportedError( | |
245 "Cannot remove from an unmodifiable list"); | |
246 } | |
247 | |
248 void removeMatching(bool test(E element)) { | |
249 throw new UnsupportedError( | |
250 "Cannot remove from an unmodifiable list"); | |
251 } | |
252 | |
253 void sort([Comparator<E> compare]) { | |
254 throw new UnsupportedError( | |
255 "Cannot modify an unmodifiable list"); | |
256 } | |
257 | |
258 void clear() { | |
259 throw new UnsupportedError( | |
260 "Cannot clear an unmodifiable list"); | |
261 } | |
262 | |
263 E removeAt(int index) { | |
264 throw new UnsupportedError( | |
265 "Cannot remove from an unmodifiable list"); | |
266 } | |
267 | |
268 E removeLast() { | |
269 throw new UnsupportedError( | |
270 "Cannot remove from an unmodifiable list"); | |
271 } | |
272 | |
273 void setRange(int start, int length, List<E> from, [int startFrom]) { | |
274 throw new UnsupportedError( | |
275 "Cannot modify an unmodifiable list"); | |
276 } | |
277 | |
278 void removeRange(int start, int length) { | |
279 throw new UnsupportedError( | |
280 "Cannot remove from an unmodifiable list"); | |
281 } | |
282 | |
283 void insertRange(int start, int length, [E initialValue]) { | |
284 throw new UnsupportedError( | |
285 "Cannot insert range in an unmodifiable list"); | |
286 } | |
287 } | |
288 | |
289 /** | |
290 * Iterates over a [List] in growing index order. | |
291 */ | |
292 class ListIterator<E> implements Iterator<E> { | |
293 final List<E> _list; | |
294 final int _length; | |
295 int _position; | |
296 E _current; | |
297 | |
298 ListIterator(List<E> list) | |
299 : _list = list, _position = -1, _length = list.length; | |
300 | |
301 bool moveNext() { | |
302 if (_list.length != _length) { | |
303 throw new ConcurrentModificationError(_list); | |
304 } | |
305 int nextPosition = _position + 1; | |
306 if (nextPosition < _length) { | |
307 _position = nextPosition; | |
308 _current = _list[nextPosition]; | |
309 return true; | |
310 } | |
311 _current = null; | |
312 return false; | |
313 } | |
314 | |
315 E get current => _current; | |
316 } | |
317 | |
318 class MappedList<S, T> extends UnmodifiableListBase<T> { | |
319 final List<S> _list; | |
320 // TODO(ahe): Restore type when feature is implemented in dart2js | |
321 // checked mode. http://dartbug.com/7733 | |
322 final /* _Transformation<S, T> */ _f; | |
323 | |
324 MappedList(this._list, T this._f(S element)); | |
325 | |
326 T operator[](int index) => _f(_list[index]); | |
327 int get length => _list.length; | |
328 } | |
329 | |
330 /** An empty fixed-length list. */ | |
331 class EmptyList<E> extends FixedLengthListBase<E> { | |
332 int get length => 0; | |
333 E operator[](int index) { throw new RangeError.value(index); } | |
334 void operator []=(int index, E value) { throw new RangeError.value(index); } | |
335 List<E> skip(int count) => this; | |
336 List<E> take(int count) => this; | |
337 List<E> get reversed => this; | |
338 void sort([int compare(E a, E b)]) {} | |
339 } | |
340 | |
341 /** | |
342 * A fixed-length view of a sub-range of another [List]. | |
343 * | |
344 * The range is described by start and end points relative | |
345 * to the other List's start or end. | |
346 * | |
347 * The range changes dynamically as the underlying list changes | |
348 * its length. | |
349 */ | |
350 abstract class SubListView<E> extends UnmodifiableListBase<E> { | |
351 final List<E> _list; | |
352 final int _start; | |
353 final int _end; | |
354 | |
355 /** | |
356 * Create a sub-list view. | |
357 * | |
358 * Both [_start] and [_end] can be given as positions | |
359 * relative to the start of [_list] (a non-negative integer) | |
360 * or relative to the end of [_list] (a negative integer or | |
361 * null, with null being at the end of the list). | |
362 */ | |
363 SubListView(this._list, this._start, this._end); | |
364 | |
365 int _absoluteIndex(int relativeIndex) { | |
366 if (relativeIndex == null) return _list.length; | |
367 if (relativeIndex < 0) { | |
368 int result = _list.length + relativeIndex; | |
369 if (result < 0) return 0; | |
370 return result; | |
371 } | |
372 if (relativeIndex > _list.length) { | |
373 return _list.length; | |
374 } | |
375 return relativeIndex; | |
376 } | |
377 | |
378 int get length { | |
379 int result = _absoluteIndex(_end) - _absoluteIndex(_start); | |
380 if (result >= 0) return result; | |
381 return 0; | |
382 } | |
383 | |
384 _createListView(int start, int end) { | |
385 if (start == null) return new EmptyList<E>(); | |
386 if (end != null) { | |
387 if (start < 0) { | |
388 if (end <= start) return new EmptyList<E>(); | |
389 } else { | |
390 if (end >= 0 && end <= start) return new EmptyList<E>(); | |
391 } | |
392 } | |
393 return new ListView(_list, start, end); | |
394 } | |
395 | |
396 _createReversedListView(int start, int end) { | |
397 if (start == null) return new EmptyList<E>(); | |
398 if (end != null) { | |
399 if (start < 0) { | |
400 if (end <= start) return new EmptyList<E>(); | |
401 } else { | |
402 if (end >= 0 && end <= start) return new EmptyList<E>(); | |
403 } | |
404 } | |
405 return new ReversedListView(_list, start, end); | |
406 } | |
407 } | |
408 | |
409 | |
410 /** | |
411 * A fixed-length view of a sub-range of a [List]. | |
412 */ | |
413 class ListView<E> extends SubListView<E> { | |
414 | |
415 ListView(List<E> list, int start, int end) : super(list, start, end); | |
416 | |
417 E operator[](int index) { | |
418 int start = _absoluteIndex(_start); | |
419 int end = _absoluteIndex(_end); | |
420 int length = end - start; | |
421 if (index < 0 || index >= length) { | |
422 throw new RangeError.range(index, 0, length); | |
423 } | |
424 return _list[start + index]; | |
425 } | |
426 | |
427 List<E> skip(int count) { | |
428 if (count is! int || count < 0) { | |
429 throw new ArgumentError(count); | |
430 } | |
431 if (_start == null) { | |
432 return new EmptyList<E>(); | |
433 } | |
434 int newStart = _start + count; | |
435 if (_start < 0 && newStart >= 0) { | |
436 return new EmptyList<E>(); | |
437 } | |
438 return _createListView(newStart, _end); | |
439 } | |
440 | |
441 List<E> take(int count) { | |
442 if (count is! int || count < 0) { | |
443 throw new ArgumentError(count); | |
444 } | |
445 if (_start == null) { | |
446 return new EmptyList<E>(); | |
447 } | |
448 int newEnd = _start + count; | |
449 if (_start < 0 && newEnd >= 0) { | |
450 newEnd = null; | |
451 } | |
452 return _createListView(_start, newEnd); | |
453 } | |
454 | |
455 List<E> get reversed => new ReversedListView(_list, _start, _end); | |
456 } | |
457 | |
458 /** | |
459 * Reversed view of a [List], or a slice of a list. | |
460 * | |
461 * The view is fixed-length and becomes invalid if the underlying | |
462 * list changes its length below the slice used by this reversed list. | |
463 * | |
464 * Start index and end index can be either positive, negative or null. | |
465 * Positive means an index relative to the start of the list, | |
466 * negative means an index relative to the end of the list, and null | |
467 * means at the end of the list (since there is no -0 integer). | |
468 */ | |
469 class ReversedListView<E> extends SubListView<E> { | |
470 | |
471 ReversedListView(List<E> list, int start, int end) | |
472 : super(list, start, end); | |
473 | |
474 E operator[](int index) { | |
475 int start = _absoluteIndex(_start); | |
476 int end = _absoluteIndex(_end); | |
477 int length = end - start; | |
478 if (index < 0 || index >= length) { | |
479 throw new RangeError.range(index, 0, length); | |
480 } | |
481 return _list[end - index - 1]; | |
482 } | |
483 | |
484 List<E> skip(int count) { | |
485 if (count is! int || count < 0) { | |
486 throw new ArgumentError(count); | |
487 } | |
488 if (_end == null) { | |
489 return _createReversedListView(_start, -count); | |
490 } | |
491 int newEnd = _end - count; | |
492 if (_end >= 0 && newEnd < 0) { | |
493 return new EmptyList<E>(); | |
494 } | |
495 return _createReversedListView(_start, newEnd); | |
496 } | |
497 | |
498 List<E> take(int count) { | |
499 if (count is! int || count < 0) { | |
500 throw new ArgumentError(count); | |
501 } | |
502 int newStart; | |
503 if (_end == null) { | |
504 newStart = -count; | |
505 } else { | |
506 newStart = _end - count; | |
507 if (_end >= 0 && newStart < 0) { | |
508 return new EmptyList<E>(); | |
509 } | |
510 } | |
511 return _createReversedListView(newStart, _end); | |
512 } | |
513 | |
514 Iterator<E> get iterator => new ReverseListIterator<E>( | |
515 _list, _absoluteIndex(_start), _absoluteIndex(_end)); | |
516 | |
517 List<E> get reversed { | |
518 return new ListView(_list, _start, _end); | |
519 } | |
520 } | |
521 | |
522 /** | |
523 * An [Iterator] over a slice of a list that access elements in reverse order. | |
524 */ | |
525 class ReverseListIterator<E> implements Iterator<E> { | |
526 final List<E> _list; | |
527 final int _start; | |
528 final int _originalLength; | |
529 int _index; | |
530 E _current; | |
531 | |
532 ReverseListIterator(List<E> list, int start, int end) | |
533 : _list = list, | |
534 _start = start, | |
535 _index = end, | |
536 _originalLength = list.length; | |
537 | |
538 bool moveNext() { | |
539 if (_list.length != _originalLength) { | |
540 throw new ConcurrentModificationError(_list); | |
541 } | |
542 if (_index <= _start) return false; | |
543 _index -= 1; | |
544 _current = _list[_index]; | |
545 return true; | |
546 } | |
547 | |
548 E get current => _current; | |
549 } | |
OLD | NEW |