OLD | NEW |
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 Loading... |
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 Loading... |
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 24 matching lines...) Expand all Loading... |
173 } | 269 } |
174 | 270 |
175 /** | 271 /** |
176 * Iterates over a [List] in growing index order. | 272 * Iterates over a [List] in growing index order. |
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; |
180 int _position; | 276 int _position; |
181 E _current; | 277 E _current; |
182 | 278 |
183 ListIterator(this._list) : _position = -1; | 279 ListIterator(List<E> list) : _list = list, _position = -1; |
184 | 280 |
185 bool moveNext() { | 281 bool moveNext() { |
186 int nextPosition = _position + 1; | 282 int nextPosition = _position + 1; |
187 if (nextPosition < _list.length) { | 283 if (nextPosition < _list.length) { |
188 _current = _list[nextPosition]; | 284 _current = _list[nextPosition]; |
189 _position = nextPosition; | 285 _position = nextPosition; |
190 return true; | 286 return true; |
191 } | 287 } |
192 _position = _list.length; | 288 _position = _list.length; |
193 _current = null; | 289 _current = null; |
194 return false; | 290 return false; |
195 } | 291 } |
196 | 292 |
197 E get current => _current; | 293 E get current => _current; |
198 } | 294 } |
199 | 295 |
200 class MappedList<S, T> extends NonExtensibleListMixin<T> { | 296 class MappedList<S, T> extends UnmodifiableListBase<T> { |
201 final List<S> _list; | 297 final List<S> _list; |
202 // TODO(ahe): Restore type when feature is implemented in dart2js | 298 // TODO(ahe): Restore type when feature is implemented in dart2js |
203 // checked mode. http://dartbug.com/7733 | 299 // checked mode. http://dartbug.com/7733 |
204 final /* _Transformation<S, T> */ _f; | 300 final /* _Transformation<S, T> */ _f; |
205 | 301 |
206 MappedList(this._list, T this._f(S element)); | 302 MappedList(this._list, T this._f(S element)); |
207 | 303 |
208 T operator[](int index) => _f(_list[index]); | 304 T operator[](int index) => _f(_list[index]); |
209 int get length => _list.length; | 305 int get length => _list.length; |
210 } | 306 } |
211 | 307 |
212 /** | 308 /** An empty fixed-length list. */ |
213 * An immutable view of a [List]. | 309 class EmptyList<E> extends FixedLengthListBase<E> { |
214 */ | 310 int get length => 0; |
215 class ListView<E> extends NonExtensibleListMixin<E> { | 311 E operator[](int index) { throw new RangeError.value(index); } |
| 312 void operator []=(int index, E value) { throw new RangeError.value(index); } |
| 313 List<E> skip(int count) => this; |
| 314 List<E> take(int count) => this; |
| 315 List<E> get reversed => this; |
| 316 void sort([int compare(E a, E b)]) {} |
| 317 } |
| 318 |
| 319 /** |
| 320 * A fixed-length view of a sub-range of another [List]. |
| 321 * |
| 322 * The range is described by start and end points relative |
| 323 * to the other List's start or end. |
| 324 * |
| 325 * The range changes dynamically as the underlying list changes |
| 326 * its length. |
| 327 */ |
| 328 abstract class SubListView<E> extends UnmodifiableListBase<E> { |
216 final List<E> _list; | 329 final List<E> _list; |
217 final int _offset; | 330 final int _start; |
218 final int _length; | 331 final int _end; |
219 | 332 |
220 /** | 333 /** |
221 * If the given length is `null` then the ListView's length is bound by | 334 * Create a sub-list view. |
222 * the backed [list]. | 335 * |
| 336 * Both [_start] and [_end] can be given as positions |
| 337 * relative to the start of [_list] (a non-negative integer) |
| 338 * or relative to the end of [_list] (a negative integer or |
| 339 * null, with null being at the end of the list). |
223 */ | 340 */ |
224 ListView(List<E> list, this._offset, this._length) : _list = list { | 341 SubListView(this._list, this._start, this._end); |
225 if (_offset is! int || _offset < 0) { | 342 |
226 throw new ArgumentError(_offset); | 343 int _absoluteIndex(int relativeIndex) { |
227 } | 344 if (relativeIndex == null) return _list.length; |
228 if (_length != null && | 345 if (relativeIndex < 0) { |
229 (_length is! int || _length < 0)) { | 346 int result = _list.length + relativeIndex; |
230 throw new ArgumentError(_length); | 347 if (result < 0) return 0; |
231 } | 348 return result; |
| 349 } |
| 350 if (relativeIndex > _list.length) { |
| 351 return _list.length; |
| 352 } |
| 353 return relativeIndex; |
232 } | 354 } |
233 | 355 |
234 int get length { | 356 int get length { |
235 int originalLength = _list.length; | 357 int result = _absoluteIndex(_end) - _absoluteIndex(_start); |
236 int skipLength = originalLength - _offset; | 358 if (result >= 0) return result; |
237 if (skipLength < 0) return 0; | 359 return 0; |
238 if (_length == null || _length > skipLength) return skipLength; | 360 } |
239 return _length; | 361 |
240 } | 362 _createListView(int start, int end) { |
| 363 if (start == null) return new EmptyList<E>(); |
| 364 if (end != null) { |
| 365 if (start < 0) { |
| 366 if (end <= start) return new EmptyList<E>(); |
| 367 } else { |
| 368 if (end >= 0 && end <= start) return new EmptyList<E>(); |
| 369 } |
| 370 } |
| 371 return new ListView(_list, start, end); |
| 372 } |
| 373 |
| 374 _createReversedListView(int start, int end) { |
| 375 if (start == null) return new EmptyList<E>(); |
| 376 if (end != null) { |
| 377 if (start < 0) { |
| 378 if (end <= start) return new EmptyList<E>(); |
| 379 } else { |
| 380 if (end >= 0 && end <= start) return new EmptyList<E>(); |
| 381 } |
| 382 } |
| 383 return new ReversedListView(_list, start, end); |
| 384 } |
| 385 } |
| 386 |
| 387 |
| 388 /** |
| 389 * A fixed-length view of a sub-range of a [List]. |
| 390 */ |
| 391 class ListView<E> extends SubListView<E> { |
| 392 |
| 393 ListView(List<E> list, int start, int end) : super(list, start, end); |
241 | 394 |
242 E operator[](int index) { | 395 E operator[](int index) { |
243 int skipIndex = index + _offset; | 396 int start = _absoluteIndex(_start); |
244 if (index < 0 || | 397 int end = _absoluteIndex(_end); |
245 (_length != null && index >= _length) || | 398 int length = end - start; |
246 index + _offset >= _list.length) { | 399 if (index < 0 || index >= length) { |
247 throw new RangeError.value(index); | 400 throw new RangeError.range(index, 0, length); |
248 } | 401 } |
249 return _list[index + _offset]; | 402 return _list[start + index]; |
250 } | 403 } |
251 | 404 |
252 ListView<E> skip(int skipCount) { | 405 List<E> skip(int count) { |
253 if (skipCount is! int || skipCount < 0) { | 406 if (count is! int || count < 0) { |
254 throw new ArgumentError(skipCount); | 407 throw new ArgumentError(count); |
255 } | 408 } |
256 return new ListView(_list, _offset + skipCount, _length); | 409 if (_start == null) { |
257 } | 410 return new EmptyList<E>(); |
258 | 411 } |
259 ListView<E> take(int takeCount) { | 412 int newStart = _start + count; |
260 if (takeCount is! int || takeCount < 0) { | 413 if (_start < 0 && newStart >= 0) { |
261 throw new ArgumentError(takeCount); | 414 return new EmptyList<E>(); |
262 } | 415 } |
263 int newLength = takeCount; | 416 return _createListView(newStart, _end); |
264 if (_length != null && takeCount > _length) newLength = _length; | 417 } |
265 return new ListView(_list, _offset, newLength); | 418 |
266 } | 419 List<E> take(int count) { |
267 } | 420 if (count is! int || count < 0) { |
| 421 throw new ArgumentError(count); |
| 422 } |
| 423 if (_start == null) { |
| 424 return new EmptyList<E>(); |
| 425 } |
| 426 int newEnd = _start + count; |
| 427 if (_start < 0 && newEnd >= 0) { |
| 428 newEnd = null; |
| 429 } |
| 430 return _createListView(_start, newEnd); |
| 431 } |
| 432 |
| 433 List<E> get reversed => new ReversedListView(_list, _start, _end); |
| 434 } |
| 435 |
| 436 /** |
| 437 * Reversed view of a [List], or a slice of a list. |
| 438 * |
| 439 * The view is fixed-length and becomes invalid if the underlying |
| 440 * list changes its length below the slice used by this reversed list. |
| 441 * |
| 442 * Start index and end index can be either positive, negative or null. |
| 443 * Positive means an index relative to the start of the list, |
| 444 * negative means an index relative to the end of the list, and null |
| 445 * means at the end of the list (since there is no -0 integer). |
| 446 */ |
| 447 class ReversedListView<E> extends SubListView<E> { |
| 448 |
| 449 ReversedListView(List<E> list, int start, int end) |
| 450 : super(list, start, end); |
| 451 |
| 452 E operator[](int index) { |
| 453 int start = _absoluteIndex(_start); |
| 454 int end = _absoluteIndex(_end); |
| 455 int length = end - start; |
| 456 if (index < 0 || index >= length) { |
| 457 throw new RangeError.range(index, 0, length); |
| 458 } |
| 459 return _list[end - index - 1]; |
| 460 } |
| 461 |
| 462 List<E> skip(int count) { |
| 463 if (count is! int || count < 0) { |
| 464 throw new ArgumentError(count); |
| 465 } |
| 466 if (_end == null) { |
| 467 return _createReversedListView(_start, -count); |
| 468 } |
| 469 int newEnd = _end - count; |
| 470 if (_end >= 0 && newEnd < 0) { |
| 471 return new EmptyList<E>(); |
| 472 } |
| 473 return _createReversedListView(_start, newEnd); |
| 474 } |
| 475 |
| 476 List<E> take(int count) { |
| 477 if (count is! int || count < 0) { |
| 478 throw new ArgumentError(count); |
| 479 } |
| 480 int newStart; |
| 481 if (_end == null) { |
| 482 newStart = -count; |
| 483 } else { |
| 484 newStart = _end - count; |
| 485 if (_end >= 0 && newStart < 0) { |
| 486 return new EmptyList<E>(); |
| 487 } |
| 488 } |
| 489 return _createReversedListView(newStart, _end); |
| 490 } |
| 491 |
| 492 Iterable<E> get iterator => new ReverseListIterator<E>( |
| 493 _list, _absoluteIndex(_start), _absoluteIndex(_end)); |
| 494 |
| 495 List<E> get reversed { |
| 496 return new ListView(_list, _start, _end); |
| 497 } |
| 498 } |
| 499 |
| 500 /** |
| 501 * An [Iterator] over a slice of a list that access elements in reverse order. |
| 502 */ |
| 503 class ReverseListIterator<E> implements Iterator<E> { |
| 504 final List<E> _list; |
| 505 final int _start; |
| 506 final int _originalLength; |
| 507 int _index; |
| 508 E _current; |
| 509 |
| 510 ReverseListIterator(List<E> list, int start, int end) |
| 511 : _list = list, |
| 512 _start = start, |
| 513 _index = end, |
| 514 _originalLength = list.length; |
| 515 |
| 516 bool moveNext() { |
| 517 if (list.length != _originalLength) { |
| 518 throw new ConcurrentModificationError(list); |
| 519 } |
| 520 if (_index <= _start) return false; |
| 521 _index -= 1; |
| 522 _current = _list[_index]; |
| 523 return true; |
| 524 } |
| 525 |
| 526 E get current => _current; |
| 527 } |
OLD | NEW |