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

Side by Side Diff: sdk/lib/collection_dev/list.dart

Issue 11896013: Add List.reversed to give a reverse fixed-length view of a list. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments, cleanup. Created 7 years, 11 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 | Annotate | Revision Log
« no previous file with comments | « sdk/lib/_internal/compiler/implementation/lib/js_array.dart ('k') | sdk/lib/core/errors.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.dev; 5 part of dart.collection.dev;
6 6
7 /** 7 /**
8 * Skeleton class for an unmodifiable [List]. 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.
9 */ 12 */
10 abstract class NonExtensibleListMixin<E> 13 abstract class ListBase<E> extends Iterable<E> implements List<E> {
11 extends Iterable<E> implements List<E> {
12
13 Iterator<E> get iterator => new ListIterator(this); 14 Iterator<E> get iterator => new ListIterator(this);
14 15
15 void forEach(f(E element)) { 16 void forEach(f(E element)) {
16 for (int i = 0; i < this.length; i++) f(this[i]); 17 for (int i = 0; i < this.length; i++) f(this[i]);
17 } 18 }
18 19
19 bool contains(E value) { 20 bool contains(E value) {
20 for (int i = 0; i < length; i++) { 21 for (int i = 0; i < length; i++) {
21 if (this[i] == value) return true; 22 if (this[i] == value) return true;
22 } 23 }
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 } 86 }
86 87
87 List<E> getRange(int start, int length) { 88 List<E> getRange(int start, int length) {
88 List<E> result = <E>[]; 89 List<E> result = <E>[];
89 for (int i = 0; i < length; i++) { 90 for (int i = 0; i < length; i++) {
90 result.add(this[start + i]); 91 result.add(this[start + i]);
91 } 92 }
92 return result; 93 return result;
93 } 94 }
94 95
96 String toString() => Collections.collectionToString(this);
97 }
98
99 /**
100 * Abstract class implementing the non-length changing operations of [List].
101 */
102 abstract class FixedLengthListBase<E> extends ListBase<E> {
103 void operator[]=(int index, E value);
104
105 List<E> get reversed => new ReversedListView<E>(this, 0, null);
106
107 void sort([Comparator<E> compare]) {
108 coreSort(this, compare);
109 }
110
111 void setRange(int start, int length, List<E> from, [int startFrom]) {
112 if (length < 0) throw new ArgumentError("length: $length");
113 if (startFrom == null) startFrom = 0;
114 for (int i = 0; i < length; i++) {
115 this[start + i] = from[startFrom + i];
116 }
117 }
118
119 void set length(int newLength) {
120 throw new UnsupportedError(
121 "Cannot change the length of a fixed-length list");
122 }
123
124 void add(E value) {
125 throw new UnsupportedError(
126 "Cannot add to a fixed-length list");
127 }
128
129 void addLast(E value) {
130 throw new UnsupportedError(
131 "Cannot add to a fixed-length list");
132 }
133
134 void addAll(Iterable<E> iterable) {
135 throw new UnsupportedError(
136 "Cannot add to a fixed-length list");
137 }
138
139 void remove(E element) {
140 throw new UnsupportedError(
141 "Cannot remove from a fixed-length list");
142 }
143
144 void removeAll(Iterable elements) {
145 throw new UnsupportedError(
146 "Cannot remove from a fixed-length list");
147 }
148
149 void retainAll(Iterable elements) {
150 throw new UnsupportedError(
151 "Cannot remove from a fixed-length list");
152 }
153
154 void removeMatching(bool test(E element)) {
155 throw new UnsupportedError(
156 "Cannot remove from a fixed-length list");
157 }
158
159 void clear() {
160 throw new UnsupportedError(
161 "Cannot clear a fixed-length list");
162 }
163
164 E removeAt(int index) {
165 throw new UnsupportedError(
166 "Cannot remove from a fixed-length list");
167 }
168
169 E removeLast() {
170 throw new UnsupportedError(
171 "Cannot remove from a fixed-length list");
172 }
173
174 void removeRange(int start, int length) {
175 throw new UnsupportedError(
176 "Cannot remove from a fixed-length list");
177 }
178
179 void insertRange(int start, int length, [E initialValue]) {
180 throw new UnsupportedError(
181 "Cannot insert range in a fixed-length list");
182 }
183 }
184
185 /**
186 * An unmodifiable [List].
187 */
188 abstract class UnmodifiableListBase<E> extends ListBase<E> {
189
95 void operator []=(int index, E value) { 190 void operator []=(int index, E value) {
96 throw new UnsupportedError( 191 throw new UnsupportedError(
97 "Cannot modify an unmodifiable list"); 192 "Cannot modify an unmodifiable list");
98 } 193 }
99 194
100 void set length(int newLength) { 195 void set length(int newLength) {
101 throw new UnsupportedError( 196 throw new UnsupportedError(
102 "Cannot change the length of an unmodifiable list"); 197 "Cannot change the length of an unmodifiable list");
103 } 198 }
104 199
(...skipping 24 matching lines...) Expand all
129 224
130 void retainAll(Iterable elements) { 225 void retainAll(Iterable elements) {
131 throw new UnsupportedError( 226 throw new UnsupportedError(
132 "Cannot remove from an unmodifiable list"); 227 "Cannot remove from an unmodifiable list");
133 } 228 }
134 229
135 void removeMatching(bool test(E element)) { 230 void removeMatching(bool test(E element)) {
136 throw new UnsupportedError( 231 throw new UnsupportedError(
137 "Cannot remove from an unmodifiable list"); 232 "Cannot remove from an unmodifiable list");
138 } 233 }
234
139 void sort([Comparator<E> compare]) { 235 void sort([Comparator<E> compare]) {
140 throw new UnsupportedError( 236 throw new UnsupportedError(
141 "Cannot modify an unmodifiable list"); 237 "Cannot modify an unmodifiable list");
142 } 238 }
143 239
144 void clear() { 240 void clear() {
145 throw new UnsupportedError( 241 throw new UnsupportedError(
146 "Cannot clear an unmodifiable list"); 242 "Cannot clear an unmodifiable list");
147 } 243 }
148 244
(...skipping 17 matching lines...) Expand all
166 "Cannot remove from an unmodifiable list"); 262 "Cannot remove from an unmodifiable list");
167 } 263 }
168 264
169 void insertRange(int start, int length, [E initialValue]) { 265 void insertRange(int start, int length, [E initialValue]) {
170 throw new UnsupportedError( 266 throw new UnsupportedError(
171 "Cannot insert range in an unmodifiable list"); 267 "Cannot insert range in an unmodifiable list");
172 } 268 }
173 } 269 }
174 270
175 /** 271 /**
176 * Iterates over a [List] in growing index order. 272 * Iterates over a [Sequence] in growing index order.
floitsch 2013/01/22 14:24:57 Bad merge?
Lasse Reichstein Nielsen 2013/01/22 14:55:12 Fixed.
177 */ 273 */
178 class ListIterator<E> implements Iterator<E> { 274 class ListIterator<E> implements Iterator<E> {
179 final List<E> _list; 275 final List<E> _list;
276 final int _initialLength;
floitsch 2013/01/22 14:24:57 I really like this change, but it should probably
Lasse Reichstein Nielsen 2013/01/22 14:55:12 Done.
180 int _position; 277 int _position;
181 E _current; 278 E _current;
182 279
183 ListIterator(this._list) : _position = -1; 280 ListIterator(List<E> list)
281 : _list = list, _position = -1, _initialLength = list.length;
184 282
185 bool moveNext() { 283 bool moveNext() {
284 if (_list.length != _initialLength) {
285 throw new ConcurrentModificationError(_list);
286 }
186 int nextPosition = _position + 1; 287 int nextPosition = _position + 1;
187 if (nextPosition < _list.length) { 288 if (nextPosition < _list.length) {
188 _current = _list[nextPosition]; 289 _current = _list[nextPosition];
189 _position = nextPosition; 290 _position = nextPosition;
190 return true; 291 return true;
191 } 292 }
192 _position = _list.length; 293 _position = _list.length;
193 _current = null; 294 _current = null;
194 return false; 295 return false;
195 } 296 }
196 297
197 E get current => _current; 298 E get current => _current;
198 } 299 }
199 300
200 class MappedList<S, T> extends NonExtensibleListMixin<T> { 301 class MappedList<S, T> extends UnmodifiableListBase<T> {
201 final List<S> _list; 302 final List<S> _list;
202 // TODO(ahe): Restore type when feature is implemented in dart2js 303 // TODO(ahe): Restore type when feature is implemented in dart2js
203 // checked mode. http://dartbug.com/7733 304 // checked mode. http://dartbug.com/7733
204 final /* _Transformation<S, T> */ _f; 305 final /* _Transformation<S, T> */ _f;
205 306
206 MappedList(this._list, T this._f(S element)); 307 MappedList(this._list, T this._f(S element));
207 308
208 T operator[](int index) => _f(_list[index]); 309 T operator[](int index) => _f(_list[index]);
209 int get length => _list.length; 310 int get length => _list.length;
210 } 311 }
211 312
212 /** 313 /** An empty fixed-length list. */
213 * An immutable view of a [List]. 314 class EmptyList<E> extends FixedLengthListBase<E> {
214 */ 315 int get length => 0;
215 class ListView<E> extends NonExtensibleListMixin<E> { 316 E operator[](int index) { throw new RangeError.value(index); }
317 void operator []=(int index, E value) { throw new RangeError.value(index); }
318 List<E> skip(int count) => this;
319 List<E> take(int count) => this;
320 List<E> get reversed => this;
321 void sort([int compare(E a, E b)]) {}
322 }
323
324 /**
325 * A fixed-length view of a sub-range of another [List].
326 *
327 * The range is described by start and end points relative
328 * to the other List's start or end.
329 *
330 * The range changes dynamically as the underlying list changes
331 * its length.
332 */
333 abstract class SubListView<E> extends FixedLengthListBase<E> {
216 final List<E> _list; 334 final List<E> _list;
217 final int _offset; 335 final int _start;
218 final int _length; 336 final int _end;
219 337
220 /** 338 /**
221 * If the given length is `null` then the ListView's length is bound by 339 * Create a sub-list view.
222 * the backed [list]. 340 *
341 * Both [_start] and [_end] can be given as positions
342 * relative to the start of [_list] (a non-negative integer)
343 * or relative to the end of [_list] (a negative integer or
344 * null, with null being at the end of the list).
223 */ 345 */
224 ListView(List<E> list, this._offset, this._length) : _list = list { 346 SubListView(this._list, this._start, this._end);
225 if (_offset is! int || _offset < 0) { 347
226 throw new ArgumentError(_offset); 348 int _absoluteIndex(int relativeIndex) {
227 } 349 if (relativeIndex == null) return _list.length;
228 if (_length != null && 350 if (relativeIndex < 0) {
229 (_length is! int || _length < 0)) { 351 int result = _list.length + relativeIndex;
230 throw new ArgumentError(_length); 352 if (result < 0) return 0;
231 } 353 return result;
354 }
355 if (relativeIndex > _list.length) {
356 return _list.length;
357 }
358 return relativeIndex;
232 } 359 }
233 360
234 int get length { 361 int get length {
235 int originalLength = _list.length; 362 int result = _absoluteIndex(_end) - _absoluteIndex(_start);
236 int skipLength = originalLength - _offset; 363 if (result >= 0) return result;
237 if (skipLength < 0) return 0; 364 return 0;
238 if (_length == null || _length > skipLength) return skipLength; 365 }
239 return _length; 366
240 } 367 _createListView(int start, int end) {
368 if (start == null) return new EmptyList<E>();
369 if (end != null) {
370 if (start < 0) {
371 if (end <= start) return new EmptyList<E>();
372 } else {
373 if (end >= 0 && end <= start) return new EmptyList<E>();
374 }
375 }
376 return new ListView(_list, start, end);
377 }
378
379 _createReversedListView(int start, int end) {
380 if (start == null) return new EmptyList<E>();
381 if (end != null) {
382 if (start < 0) {
383 if (end <= start) return new EmptyList<E>();
384 } else {
385 if (end >= 0 && end <= start) return new EmptyList<E>();
386 }
387 }
388 return new ReversedListView(_list, start, end);
389 }
390 }
391
392
393 /**
394 * A fixed-length view of a sub-range of a [List].
395 */
396 class ListView<E> extends SubListView<E> {
397
398 ListView(List<E> list, int start, int end) : super(list, start, end);
241 399
242 E operator[](int index) { 400 E operator[](int index) {
243 int skipIndex = index + _offset; 401 int start = _absoluteIndex(_start);
244 if (index < 0 || 402 int end = _absoluteIndex(_end);
245 (_length != null && index >= _length) || 403 int length = end - start;
246 index + _offset >= _list.length) { 404 if (index < 0 || index >= length) {
247 throw new RangeError.value(index); 405 throw new RangeError.range(index, 0, length);
248 } 406 }
249 return _list[index + _offset]; 407 return _list[start + index];
250 } 408 }
251 409
252 ListView<E> skip(int skipCount) { 410 void operator []=(int index, E value) {
floitsch 2013/01/22 14:24:57 Not in this CL. I'm not even sure I agree.
Lasse Reichstein Nielsen 2013/01/22 14:55:12 Moved to separate CL.
253 if (skipCount is! int || skipCount < 0) { 411 int start = _absoluteIndex(_start);
254 throw new ArgumentError(skipCount); 412 int end = _absoluteIndex(_end);
255 } 413 int length = end - start;
256 return new ListView(_list, _offset + skipCount, _length); 414 if (index < 0 || index >= length) {
257 } 415 throw new RangeError.range(index, 0, length);
258 416 }
259 ListView<E> take(int takeCount) { 417 _list[start + index] = value;
260 if (takeCount is! int || takeCount < 0) { 418 }
261 throw new ArgumentError(takeCount); 419
262 } 420 List<E> skip(int count) {
263 int newLength = takeCount; 421 if (count is! int || count < 0) {
264 if (_length != null && takeCount > _length) newLength = _length; 422 throw new ArgumentError(count);
265 return new ListView(_list, _offset, newLength); 423 }
266 } 424 if (_start == null) {
267 } 425 return new EmptyList<E>();
floitsch 2013/01/22 14:24:57 Can this happen? If _start is [null] then we would
Lasse Reichstein Nielsen 2013/01/22 14:55:12 I dare not assume it can't happen. Call it safety
426 }
427 int newStart = _start + count;
428 if (_start < 0 && newStart >= 0) {
429 return new EmptyList<E>();
430 }
431 return _createListView(newStart, _end);
432 }
433
434 List<E> take(int count) {
435 if (count is! int || count < 0) {
436 throw new ArgumentError(count);
437 }
438 if (_start == null) {
439 return new EmptyList<E>();
floitsch 2013/01/22 14:24:57 ditto.
Lasse Reichstein Nielsen 2013/01/22 14:55:12 Same.
440 }
441 int newEnd = _start + count;
442 if (_start < 0 && newEnd >= 0) {
443 newEnd = null;
444 }
445 return _createListView(_start, newEnd);
446 }
447
448 List<E> get reversed => new ReversedListView(_list, _start, _end);
449
450 void sort([int compare(E first, E second)]) {
floitsch 2013/01/22 14:24:57 Different CL together with []=.
Lasse Reichstein Nielsen 2013/01/22 14:55:12 Done.
451 if (compare == null) compare = Comparable.compare;
452 // TODO(lrn): Make a way to sort a slice of a list using core sort.
453 int start = _absoluteIndex(_start);
454 int end = _absoluteIndex(_end);
455 List<E> slice = _list.getRange(start, end);
456 slice.sort(compare);
457 _list.setRange(start, end - start, slice);
458 }
459 }
460
461 /**
462 * Reversed view of a [List], or a slice of a list.
463 *
464 * The view is fixed-length and becomes invalid if the underlying
465 * list changes its length below the slice used by this reversed list.
466 *
467 * Start index and end index can be either positive, negative or null.
468 * Positive means an index relative to the start of the list,
469 * negative means an index relative to the end of the list, and null
470 * means at the end of the list (since there is no -0 integer).
471 */
472 class ReversedListView<E> extends SubListView<E> {
473
474 ReversedListView(List<E> list, int start, int end)
475 : super(list, start, end);
476
477 E operator[](int index) {
478 int start = _absoluteIndex(_start);
479 int end = _absoluteIndex(_end);
480 int length = end - start;
481 if (index < 0 || index >= length) {
482 throw new RangeError.range(index, 0, length);
483 }
484 return _list[end - index - 1];
485 }
486
487 void operator []=(int index, E value) {
floitsch 2013/01/22 14:24:57 Different CL.
Lasse Reichstein Nielsen 2013/01/22 14:55:12 Done.
488 int start = _absoluteIndex(_start);
489 int end = _absoluteIndex(_end);
490 int length = end - start;
491 if (index < 0 || index >= length) {
492 throw new RangeError.range(index, 0, length);
493 }
494 _list[end - index - 1] = value;
495 }
496
497 List<E> skip(int count) {
498 if (count is! int || count < 0) {
499 throw new ArgumentError(count);
500 }
501 if (_end == null) {
502 return _createReversedListView(_start, -count);
503 }
504 int newEnd = _end - count;
505 if (_end >= 0 && newEnd < 0) {
506 return new EmptyList<E>();
507 }
508 return _createReversedListView(_start, newEnd);
509 }
510
511 List<E> take(int count) {
512 if (count is! int || count < 0) {
513 throw new ArgumentError(count);
514 }
515 int newStart;
516 if (_end == null) {
517 newStart = -count;
518 } else {
519 newStart = _end - count;
520 if (_end >= 0 && newStart < 0) {
521 return new EmptyList<E>();
522 }
523 }
524 return _createReversedListView(newStart, _end);
525 }
526
527 Iterable<E> get iterator => new ReverseListIterator<E>(
528 _list, _absoluteIndex(_start), _absoluteIndex(_end));
529
530 List<E> get reversed {
531 return new ListView(_list, _start, _end);
532 }
533
534 void sort([int compare(E first, E second)]) {
floitsch 2013/01/22 14:24:57 different CL.
Lasse Reichstein Nielsen 2013/01/22 14:55:12 Done.
535 if (compare == null) compare = Comparable.compare;
536 // TODO(lrn): Make a way to sort a slice of a list using core sort.
537 int start = _absoluteIndex(_start);
538 int end = _absoluteIndex(_end);
539 List<E> slice = _list.getRange(start, end);
540 slice.sort((E a, E b) => compare(b, a));
541 _list.setRange(start, end - start, slice);
542 }
543 }
544
545 /**
546 * An [Iterator] over a slice of a list that access elements in reverse order.
547 */
548 class ReverseListIterator<E> implements Iterator<E> {
549 final List<E> _list;
550 final int _start;
551 final int _originalLength;
552 int _index;
553 E _current;
554
555 ReverseListIterator(List<E> list, int start, int end)
556 : _list = list,
557 _start = start,
558 _index = end,
559 _originalLength = list.length;
560
561 bool moveNext() {
562 if (list.length != _originalLength) {
563 throw new ConcurrentModificationError(list);
564 }
565 if (_index <= _start) return false;
566 _index -= 1;
567 _current = _list[_index];
568 return true;
569 }
570
571 E get current => _current;
572 }
OLDNEW
« no previous file with comments | « sdk/lib/_internal/compiler/implementation/lib/js_array.dart ('k') | sdk/lib/core/errors.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698