Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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.core; | 5 part of dart.core; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * A [List] is an indexable collection with a length. It can be of | 8 * A [List] is an indexable collection with a length. It can be of |
| 9 * fixed size or extendable. | 9 * fixed size or extendable. |
| 10 */ | 10 */ |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 78 void addLast(E value); | 78 void addLast(E value); |
| 79 | 79 |
| 80 /** | 80 /** |
| 81 * Appends all elements of the [iterable] to the end of this list. | 81 * Appends all elements of the [iterable] to the end of this list. |
| 82 * Extends the length of the list by the number of elements in [iterable]. | 82 * Extends the length of the list by the number of elements in [iterable]. |
| 83 * Throws an [UnsupportedError] if this list is not extensible. | 83 * Throws an [UnsupportedError] if this list is not extensible. |
| 84 */ | 84 */ |
| 85 void addAll(Iterable<E> iterable); | 85 void addAll(Iterable<E> iterable); |
| 86 | 86 |
| 87 /** | 87 /** |
| 88 * Returns a reversed fixed-length view of this [List]. | |
| 89 * | |
| 90 * The reversed list has elements in the opposite order of this list. | |
| 91 * It is backed by this list, but will stop working if this list | |
| 92 * becomes shorter than its current length. | |
| 93 */ | |
| 94 List<T> get reversed => new ReversedList(this, 0, length); | |
| 95 | |
| 96 /** | |
| 88 * Sorts the list according to the order specified by the [compare] function. | 97 * Sorts the list according to the order specified by the [compare] function. |
| 89 * | 98 * |
| 90 * The [compare] function must act as a [Comparator]. | 99 * The [compare] function must act as a [Comparator]. |
| 91 * The default [List] implementations use [Comparable.compare] if | 100 * The default [List] implementations use [Comparable.compare] if |
| 92 * [compare] is omitted. | 101 * [compare] is omitted. |
| 93 */ | 102 */ |
| 94 void sort([int compare(E a, E b)]); | 103 void sort([int compare(E a, E b)]); |
| 95 | 104 |
| 96 /** | 105 /** |
| 97 * Returns the first index of [element] in the list. | 106 * Returns the first index of [element] in the list. |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 185 * If [start] is the length of the list, this method inserts the | 194 * If [start] is the length of the list, this method inserts the |
| 186 * range at the end of the list. | 195 * range at the end of the list. |
| 187 * Throws an [ArgumentError] if [length] is negative. | 196 * Throws an [ArgumentError] if [length] is negative. |
| 188 * Throws an [RangeError] if [start] is negative or if | 197 * Throws an [RangeError] if [start] is negative or if |
| 189 * [start] is greater than the length of the list. | 198 * [start] is greater than the length of the list. |
| 190 */ | 199 */ |
| 191 void insertRange(int start, int length, [E fill]); | 200 void insertRange(int start, int length, [E fill]); |
| 192 } | 201 } |
| 193 | 202 |
| 194 /** | 203 /** |
| 195 * An unmodifiable [List]. | 204 * Class implementing the read-operations on [List]. |
| 205 * | |
| 206 * Implements all operations except [:operator[]:] and [:length:] that does not | |
| 207 * modify the list in terms of those two. | |
| 196 */ | 208 */ |
| 197 abstract class NonExtensibleListMixin<E> | 209 abstract class BaseListMixin<E> extends Iterable<E> implements List<E> { |
|
floitsch
2013/01/21 14:38:06
These classes are no longer in core.
Lasse Reichstein Nielsen
2013/01/22 10:18:52
Moved to collection-dev.
| |
| 198 extends Iterable<E> implements List<E> { | |
| 199 | |
| 200 Iterator<E> get iterator => new ListIterator(this); | 210 Iterator<E> get iterator => new ListIterator(this); |
| 201 | 211 |
| 202 void forEach(f(E element)) { | 212 void forEach(f(E element)) { |
| 203 for (int i = 0; i < this.length; i++) f(this[i]); | 213 for (int i = 0; i < this.length; i++) f(this[i]); |
| 204 } | 214 } |
| 205 | 215 |
| 206 bool contains(E value) { | 216 bool contains(E value) { |
| 207 for (int i = 0; i < length; i++) { | 217 for (int i = 0; i < length; i++) { |
| 208 if (this[i] == value) return true; | 218 if (this[i] == value) return true; |
| 209 } | 219 } |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 271 throw new StateError("More than one element"); | 281 throw new StateError("More than one element"); |
| 272 } | 282 } |
| 273 | 283 |
| 274 List<E> getRange(int start, int length) { | 284 List<E> getRange(int start, int length) { |
| 275 List<E> result = <E>[]; | 285 List<E> result = <E>[]; |
| 276 for (int i = 0; i < length; i++) { | 286 for (int i = 0; i < length; i++) { |
| 277 result.add(this[start + i]); | 287 result.add(this[start + i]); |
| 278 } | 288 } |
| 279 return result; | 289 return result; |
| 280 } | 290 } |
| 291 } | |
| 292 | |
| 293 /** | |
| 294 * Abstract class implementing the non-length changing operations of [List]. | |
| 295 */ | |
| 296 abstract class FixedLengthListMixin<E> extends BaseListMixin<E> { | |
|
floitsch
2013/01/21 14:38:06
Can't be a mixin, since it extends (or mixins) Bas
Lasse Reichstein Nielsen
2013/01/22 10:18:52
True, so it needs a better name.
Just FixedLengthL
| |
| 297 void operator[]=(int index, E value); | |
| 298 | |
| 299 List<E> get reversed => new ReversedList<E>(this, 0, length); | |
| 300 | |
| 301 void sort([Comparator<E> compare]) { | |
| 302 coreSort(this, compare); | |
| 303 } | |
| 304 | |
| 305 void setRange(int start, int length, List<E> from, [int startFrom]) { | |
| 306 if (length < 0) throw new ArgumentError("length: $length"); | |
| 307 if (startFrom == null) startFrom = 0; | |
| 308 for (int i = 0; i < length; i++) { | |
| 309 this[from + i] = from[startFrom + i]; | |
| 310 } | |
| 311 } | |
| 312 | |
| 313 void set length(int newLength) { | |
| 314 throw new UnsupportedError( | |
| 315 "Cannot change the length of a fixed-length list"); | |
| 316 } | |
| 317 | |
| 318 void add(E value) { | |
| 319 throw new UnsupportedError( | |
| 320 "Cannot add to a fixed-length list"); | |
| 321 } | |
| 322 | |
| 323 void addLast(E value) { | |
| 324 throw new UnsupportedError( | |
| 325 "Cannot add to a fixed-length list"); | |
| 326 } | |
| 327 | |
| 328 void addAll(Iterable<E> iterable) { | |
| 329 throw new UnsupportedError( | |
| 330 "Cannot add to a fixed-length list"); | |
| 331 } | |
| 332 | |
| 333 void remove(E element) { | |
| 334 throw new UnsupportedError( | |
| 335 "Cannot remove from a fixed-length list"); | |
| 336 } | |
| 337 | |
| 338 void removeAll(Iterable elements) { | |
| 339 throw new UnsupportedError( | |
| 340 "Cannot remove from a fixed-length list"); | |
| 341 } | |
| 342 | |
| 343 void retainAll(Iterable elements) { | |
| 344 throw new UnsupportedError( | |
| 345 "Cannot remove from a fixed-length list"); | |
| 346 } | |
| 347 | |
| 348 void removeMatching(bool test(E element)) { | |
| 349 throw new UnsupportedError( | |
| 350 "Cannot remove from a fixed-length list"); | |
| 351 } | |
| 352 | |
| 353 void clear() { | |
| 354 throw new UnsupportedError( | |
| 355 "Cannot clear a fixed-length list"); | |
| 356 } | |
| 357 | |
| 358 E removeAt(int index) { | |
| 359 throw new UnsupportedError( | |
| 360 "Cannot remove from a fixed-length list"); | |
| 361 } | |
| 362 | |
| 363 E removeLast() { | |
| 364 throw new UnsupportedError( | |
| 365 "Cannot remove from a fixed-length list"); | |
| 366 } | |
| 367 | |
| 368 void removeRange(int start, int length) { | |
| 369 throw new UnsupportedError( | |
| 370 "Cannot remove from a fixed-length list"); | |
| 371 } | |
| 372 | |
| 373 void insertRange(int start, int length, [E initialValue]) { | |
| 374 throw new UnsupportedError( | |
| 375 "Cannot insert range in a fixed-length list"); | |
| 376 } | |
| 377 } | |
| 378 | |
| 379 /** | |
| 380 * An unmodifiable [List]. | |
| 381 */ | |
| 382 abstract class UnmodifiableListMixin<E> extends BaseListMixin<E> { | |
| 281 | 383 |
| 282 void operator []=(int index, E value) { | 384 void operator []=(int index, E value) { |
| 283 throw new UnsupportedError( | 385 throw new UnsupportedError( |
| 284 "Cannot modify an unmodifiable list"); | 386 "Cannot modify an unmodifiable list"); |
| 285 } | 387 } |
| 286 | 388 |
| 287 void set length(int newLength) { | 389 void set length(int newLength) { |
| 288 throw new UnsupportedError( | 390 throw new UnsupportedError( |
| 289 "Cannot change the length of an unmodifiable list"); | 391 "Cannot change the length of an unmodifiable list"); |
| 290 } | 392 } |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 378 return true; | 480 return true; |
| 379 } | 481 } |
| 380 _position = _list.length; | 482 _position = _list.length; |
| 381 _current = null; | 483 _current = null; |
| 382 return false; | 484 return false; |
| 383 } | 485 } |
| 384 | 486 |
| 385 E get current => _current; | 487 E get current => _current; |
| 386 } | 488 } |
| 387 | 489 |
| 388 class MappedList<S, T> extends NonExtensibleListMixin<T> { | 490 class MappedList<S, T> extends UnmodifiableListMixin<T> { |
| 389 final List<S> _list; | 491 final List<S> _list; |
| 390 // TODO(ahe): Restore type when feature is implemented in dart2js | 492 // TODO(ahe): Restore type when feature is implemented in dart2js |
| 391 // checked mode. http://dartbug.com/7733 | 493 // checked mode. http://dartbug.com/7733 |
| 392 final /* _Transformation<S, T> */ _f; | 494 final /* _Transformation<S, T> */ _f; |
| 393 | 495 |
| 394 MappedList(this._list, T this._f(S element)); | 496 MappedList(this._list, T this._f(S element)); |
| 395 | 497 |
| 396 T operator[](int index) => _f(_list[index]); | 498 T operator[](int index) => _f(_list[index]); |
| 397 int get length => _list.length; | 499 int get length => _list.length; |
| 398 } | 500 } |
| 399 | 501 |
| 502 /** An empty fixed-length list. */ | |
| 503 class EmptyList<E> extends FixedLengthListMixin<E> { | |
| 504 int get length => 0; | |
| 505 E operator[](int index) { throw new ArgumentError(index); } | |
|
floitsch
2013/01/21 14:38:06
RangeError
Lasse Reichstein Nielsen
2013/01/22 10:18:52
Done.
| |
| 506 void operator[]=(int index, E value) { throw new ArgumentError(index); } | |
| 507 } | |
| 508 | |
| 400 /** | 509 /** |
| 401 * An immutable view of a [List]. | 510 * An unmodifiable view of a [List]. |
| 402 */ | 511 */ |
| 403 class ListView<E> extends NonExtensibleListMixin<E> { | 512 class ListView<E> extends UnmodifiableListMixin<E> { |
| 404 final List<E> _list; | 513 final List<E> _list; |
| 405 final int _offset; | 514 final int _offset; |
| 406 final int _length; | 515 final int _length; |
| 407 | 516 |
| 408 /** | 517 /** |
| 409 * If the given length is `null` then the ListView's length is bound by | 518 * If the given length is `null` then the ListView's length is bound by |
| 410 * the backed [list]. | 519 * the backed [list]. |
| 411 */ | 520 */ |
| 412 ListView(List<E> list, this._offset, this._length) : _list = list { | 521 ListView(List<E> list, this._offset, this._length) : _list = list { |
| 413 if (_offset is! int || _offset < 0) { | 522 if (_offset is! int || _offset < 0) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 445 } | 554 } |
| 446 | 555 |
| 447 ListView<E> take(int takeCount) { | 556 ListView<E> take(int takeCount) { |
| 448 if (takeCount is! int || takeCount < 0) { | 557 if (takeCount is! int || takeCount < 0) { |
| 449 throw new ArgumentError(takeCount); | 558 throw new ArgumentError(takeCount); |
| 450 } | 559 } |
| 451 int newLength = takeCount; | 560 int newLength = takeCount; |
| 452 if (_length != null && takeCount > _length) newLength = _length; | 561 if (_length != null && takeCount > _length) newLength = _length; |
| 453 return new ListView(_list, _offset, newLength); | 562 return new ListView(_list, _offset, newLength); |
| 454 } | 563 } |
| 564 | |
| 565 List<E> get reversed => new ReversedList(_list, _offset, _offset + _length); | |
| 566 | |
| 567 String toString() => Collections.collectionToString(this); | |
| 455 } | 568 } |
| 569 | |
| 570 /** | |
| 571 * Reversed view of a [List], or a slice of a list. | |
| 572 * | |
| 573 * The view is fixed-length and becomes invalid if the underlying | |
| 574 * list changes its length below the slice used by this reversed list. | |
|
floitsch
2013/01/21 14:38:06
That's now how iterables work. And ReversedList (l
Lasse Reichstein Nielsen
2013/01/21 14:43:40
So what should it do?
| |
| 575 */ | |
| 576 class ReversedList<E> extends FixedLengthListMixin<E> { | |
| 577 final List<E> _list; | |
| 578 final int _start; | |
| 579 final int _end; | |
| 580 ReversedList(List<E> list, int start, int end) | |
| 581 : _list = list, _start = start, _end = end; | |
| 582 | |
| 583 int get length => _end - _start; | |
| 584 | |
| 585 E operator[](int index) { | |
| 586 if (_list.length < _end) throw new StateError("Concurrent modification"); | |
| 587 int length = _end - _start; | |
| 588 if (index < 0 || index > length) { | |
| 589 throw new RangeError("$index not in range 0..$length"); | |
| 590 } | |
| 591 return _list[_end - index - 1]; | |
| 592 } | |
| 593 | |
| 594 void operator[]=(int index, E value) { | |
| 595 if (_list.length < _end) throw new StateError("Concurrent modification"); | |
| 596 int length = _end - _start; | |
| 597 if (index < 0 || index > length) { | |
| 598 throw new RangeError("$index not in range 0..$length"); | |
| 599 } | |
| 600 _list[_end - index - 1] = value; | |
| 601 } | |
| 602 | |
| 603 Iterable<E> get iterator => new ReverseListIterator<E>(_list, _start, _end); | |
| 604 | |
| 605 List<E> take(int count) { | |
| 606 if (count is! int || count < 0) { | |
| 607 throw new ArgumentError(count); | |
| 608 } | |
| 609 int length = _end - _start; | |
| 610 if (count > length) count = length; | |
| 611 return new ReversedList(_list, _end - count, _end); | |
| 612 } | |
| 613 | |
| 614 List<E> skip(int count) { | |
| 615 if (count is! int || count < 0) { | |
| 616 throw new ArgumentError(count); | |
| 617 } | |
| 618 int length = _end - _start; | |
| 619 if (count >= length) return new EmptyList(); | |
| 620 return new ReversedList(_list, _start, _end - count); | |
| 621 } | |
| 622 | |
| 623 void sort([int compare(E first, E second)]) { | |
| 624 if (compare == null) compare = Comparable.compare; | |
| 625 // TODO(lrn): Make a way to sort a slice of a list using core sort. | |
| 626 List<E> slice = _list.getRange(_start, _end); | |
| 627 slice.sort((E a, E b) => compare(b, a)); | |
| 628 _list.setRange(_start, slice.length, slice); | |
| 629 } | |
| 630 | |
| 631 List<E> get reversed { | |
| 632 return new ListView(_list, _start, _end - _start); | |
| 633 } | |
| 634 | |
| 635 String toString() => Collections.collectionToString(this); | |
| 636 } | |
| 637 | |
| 638 /** | |
| 639 * An [Iterator] over a slice of a list that access elements in reverse order. | |
| 640 */ | |
| 641 class ReverseListIterator<E> implements Iterator<E> { | |
| 642 final List<E> _list; | |
| 643 final int _start; | |
| 644 int _index; | |
| 645 E _current; | |
| 646 | |
| 647 ReverseListIterator(List<E> list, int start, int end) | |
| 648 : _list = list, _start = start, _index = end; | |
| 649 | |
| 650 bool moveNext() { | |
| 651 if (_index <= _start) return false; | |
| 652 _index -= 1; | |
| 653 _current = _list[_index]; | |
| 654 return true; | |
| 655 } | |
| 656 | |
| 657 E get current => _current; | |
| 658 } | |
| OLD | NEW |