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

Side by Side Diff: tool/input_sdk/lib/core/list.dart

Issue 1153003003: fixes #40, extension methods for primitive types (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 6 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) 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 * An indexable collection of objects with a length. 8 * An indexable collection of objects with a length.
9 * 9 *
10 * Subclasses of this class implement different kinds of lists. 10 * Subclasses of this class implement different kinds of lists.
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 * temporarily and is restored before continuing the iteration, the iterator 44 * temporarily and is restored before continuing the iteration, the iterator
45 * does not detect it. 45 * does not detect it.
46 * 46 *
47 * It is generally not allowed to modify the list's length (adding or removing 47 * It is generally not allowed to modify the list's length (adding or removing
48 * elements) while an operation on the list is being performed, 48 * elements) while an operation on the list is being performed,
49 * for example during a call to [forEach] or [sort]. 49 * for example during a call to [forEach] or [sort].
50 * Changing the list's length while it is being iterated, either by iterating it 50 * Changing the list's length while it is being iterated, either by iterating it
51 * directly or through iterating an [Iterable] that is backed by the list, will 51 * directly or through iterating an [Iterable] that is backed by the list, will
52 * break the iteration. 52 * break the iteration.
53 */ 53 */
54 @SupportJsExtensionMethod() 54 abstract class List<E> implements Iterable<E> {
55 @JsPeerInterface(name: 'Array')
56 abstract class List<E> implements Iterable<E>, EfficientLength {
57 /** 55 /**
58 * Creates a list of the given length. 56 * Creates a list of the given length.
59 * 57 *
60 * The created list is fixed-length if [length] is provided. 58 * The created list is fixed-length if [length] is provided.
61 * 59 *
62 * List fixedLengthList = new List(3); 60 * List fixedLengthList = new List(3);
63 * fixedLengthList.length; // 3 61 * fixedLengthList.length; // 3
64 * fixedLengthList.length = 1; // Error 62 * fixedLengthList.length = 1; // Error
65 * 63 *
66 * The list has length 0 and is growable if [length] is omitted. 64 * The list has length 0 and is growable if [length] is omitted.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 * 101 *
104 * Creates a list with [length] positions and fills it with values created by 102 * Creates a list with [length] positions and fills it with values created by
105 * calling [generator] for each index in the range `0` .. `length - 1` 103 * calling [generator] for each index in the range `0` .. `length - 1`
106 * in increasing order. 104 * in increasing order.
107 * 105 *
108 * new List<int>.generate(3, (int index) => index * index); // [0, 1, 4] 106 * new List<int>.generate(3, (int index) => index * index); // [0, 1, 4]
109 * 107 *
110 * The created list is fixed-length unless [growable] is true. 108 * The created list is fixed-length unless [growable] is true.
111 */ 109 */
112 factory List.generate(int length, E generator(int index), 110 factory List.generate(int length, E generator(int index),
113 { bool growable: true }) { 111 { bool growable: true }) {
114 List<E> result; 112 List<E> result;
115 if (growable) { 113 if (growable) {
116 result = <E>[]..length = length; 114 result = <E>[]..length = length;
117 } else { 115 } else {
118 result = new List<E>(length); 116 result = new List<E>(length);
119 } 117 }
120 for (int i = 0; i < length; i++) { 118 for (int i = 0; i < length; i++) {
121 result[i] = generator(i); 119 result[i] = generator(i);
122 } 120 }
123 return result; 121 return result;
124 } 122 }
125 123
126 checkMutable(reason) {
127 /* TODO(jacobr): implement.
128 if (this is !JSMutableArray) {
129 throw new UnsupportedError(reason);
130 }
131 * */
132 }
133
134 checkGrowable(reason) {
135 /* TODO(jacobr): implement
136 if (this is !JSExtendableArray) {
137 throw new UnsupportedError(reason);
138 }
139 * */
140 }
141
142 Iterable<E> where(bool f(E element)) {
143 return new IterableMixinWorkaround<E>().where(this, f);
144 }
145
146 Iterable expand(Iterable f(E element)) {
147 return IterableMixinWorkaround.expand(this, f);
148 }
149
150 void forEach(void f(E element)) {
151 int length = this.length;
152 for (int i = 0; i < length; i++) {
153 f(JS('', '#[#]', this, i));
154 if (length != this.length) {
155 throw new ConcurrentModificationError(this);
156 }
157 }
158 }
159
160 Iterable map(f(E element)) {
161 return IterableMixinWorkaround.mapList(this, f);
162 }
163
164 String join([String separator = ""]) {
165 var list = new List(this.length);
166 for (int i = 0; i < this.length; i++) {
167 list[i] = "${this[i]}";
168 }
169 return JS('String', "#.join(#)", list, separator);
170 }
171
172 Iterable<E> take(int n) {
173 return new IterableMixinWorkaround<E>().takeList(this, n);
174 }
175
176 Iterable<E> takeWhile(bool test(E value)) {
177 return new IterableMixinWorkaround<E>().takeWhile(this, test);
178 }
179
180 Iterable<E> skip(int n) {
181 return new IterableMixinWorkaround<E>().skipList(this, n);
182 }
183
184 Iterable<E> skipWhile(bool test(E value)) {
185 return new IterableMixinWorkaround<E>().skipWhile(this, test);
186 }
187
188 E reduce(E combine(E value, E element)) {
189 return IterableMixinWorkaround.reduce(this, combine);
190 }
191
192 fold(initialValue, combine(previousValue, E element)) {
193 return IterableMixinWorkaround.fold(this, initialValue, combine);
194 }
195
196 E firstWhere(bool test(E value), {E orElse()}) {
197 return IterableMixinWorkaround.firstWhere(this, test, orElse);
198 }
199
200 E lastWhere(bool test(E value), {E orElse()}) {
201 return IterableMixinWorkaround.lastWhereList(this, test, orElse);
202 }
203
204 E singleWhere(bool test(E value)) {
205 return IterableMixinWorkaround.singleWhere(this, test);
206 }
207
208 E elementAt(int index) {
209 return this[index];
210 }
211
212 E get first {
213 if (length > 0) return this[0];
214 throw new StateError("No elements");
215 }
216
217 E get last {
218 if (length > 0) return this[length - 1];
219 throw new StateError("No elements");
220 }
221
222 E get single {
223 if (length == 1) return this[0];
224 if (length == 0) throw new StateError("No elements");
225 throw new StateError("More than one element");
226 }
227
228 bool any(bool f(E element)) => IterableMixinWorkaround.any(this, f);
229
230 bool every(bool f(E element)) => IterableMixinWorkaround.every(this, f);
231
232 bool contains(Object other) {
233 for (int i = 0; i < length; i++) {
234 if (this[i] == other) return true;
235 }
236 return false;
237 }
238
239 bool get isEmpty => length == 0;
240
241 bool get isNotEmpty => !isEmpty;
242
243 String toString() => ListBase.listToString(this);
244
245 List<E> toList({ bool growable: true }) {
246 // TODO(vsm): Enforce growable / non-growable.
247 // See: https://github.com/dart-lang/dev_compiler/issues/175
248 return JS('', 'dart.setType(#.slice(), core.List\$(#))', this, E);
249 }
250
251 Set<E> toSet() => new Set<E>.from(this);
252
253 Iterator<E> get iterator => new ListIterator<E>(this);
254
255 int get hashCode => Primitives.objectHashCode(this);
256
257 // BORDER XXXX
258
259 /** 124 /**
260 * Returns the object at the given [index] in the list 125 * Returns the object at the given [index] in the list
261 * or throws a [RangeError] if [index] is out of bounds. 126 * or throws a [RangeError] if [index] is out of bounds.
262 */ 127 */
263 E operator [](int index) { 128 E operator [](int index);
264 if (index is !int) throw new ArgumentError(index);
265 if (index >= length || index < 0) throw new RangeError.value(index);
266 return JS('var', '#[#]', this, index);
267 }
268 129
269 /** 130 /**
270 * Sets the value at the given [index] in the list to [value] 131 * Sets the value at the given [index] in the list to [value]
271 * or throws a [RangeError] if [index] is out of bounds. 132 * or throws a [RangeError] if [index] is out of bounds.
272 */ 133 */
273 void operator []=(int index, E value) { 134 void operator []=(int index, E value);
274 checkMutable('indexed set');
275 if (index is !int) throw new ArgumentError(index);
276 if (index >= length || index < 0) throw new RangeError.value(index);
277 JS('void', r'#[#] = #', this, index, value);
278 }
279 135
280 /** 136 /**
281 * Returns the number of objects in this list. 137 * Returns the number of objects in this list.
282 * 138 *
283 * The valid indices for a list are `0` through `length - 1`. 139 * The valid indices for a list are `0` through `length - 1`.
284 */ 140 */
285 int get length => JS('JSUInt32', r'#.length', this); 141 int get length;
286 142
287 /** 143 /**
288 * Changes the length of this list. 144 * Changes the length of this list.
289 * 145 *
290 * If [newLength] is greater than 146 * If [newLength] is greater than
291 * the current length, entries are initialized to [:null:]. 147 * the current length, entries are initialized to [:null:].
292 * 148 *
293 * Throws an [UnsupportedError] if the list is fixed-length. 149 * Throws an [UnsupportedError] if the list is fixed-length.
294 */ 150 */
295 void set length(int newLength) { 151 void set length(int newLength);
296 if (newLength is !int) throw new ArgumentError(newLength);
297 if (newLength < 0) throw new RangeError.value(newLength);
298 checkGrowable('set length');
299 JS('void', r'#.length = #', this, newLength);
300 }
301 152
302 /** 153 /**
303 * Adds [value] to the end of this list, 154 * Adds [value] to the end of this list,
304 * extending the length by one. 155 * extending the length by one.
305 * 156 *
306 * Throws an [UnsupportedError] if the list is fixed-length. 157 * Throws an [UnsupportedError] if the list is fixed-length.
307 */ 158 */
308 void add(E value) { 159 void add(E value);
309 checkGrowable('add');
310 JS('void', r'#.push(#)', this, value);
311 }
312 160
313 /** 161 /**
314 * Appends all objects of [iterable] to the end of this list. 162 * Appends all objects of [iterable] to the end of this list.
315 * 163 *
316 * Extends the length of the list by the number of objects in [iterable]. 164 * Extends the length of the list by the number of objects in [iterable].
317 * Throws an [UnsupportedError] if this list is fixed-length. 165 * Throws an [UnsupportedError] if this list is fixed-length.
318 */ 166 */
319 void addAll(Iterable<E> iterable) { 167 void addAll(Iterable<E> iterable);
320 for (E e in iterable) {
321 this.add(e);
322 }
323 }
324 168
325 /** 169 /**
326 * Returns an [Iterable] of the objects in this list in reverse order. 170 * Returns an [Iterable] of the objects in this list in reverse order.
327 */ 171 */
328 Iterable<E> get reversed => 172 Iterable<E> get reversed;
329 new IterableMixinWorkaround<E>().reversedList(this);
330 173
331 /** 174 /**
332 * Sorts this list according to the order specified by the [compare] function. 175 * Sorts this list according to the order specified by the [compare] function.
333 * 176 *
334 * The [compare] function must act as a [Comparator]. 177 * The [compare] function must act as a [Comparator].
335
336 * List<String> numbers = ['one', 'two', 'three', 'four']; 178 * List<String> numbers = ['one', 'two', 'three', 'four'];
337 * // Sort from shortest to longest. 179 * // Sort from shortest to longest.
338 * numbers.sort((x, y) => x.length.compareTo(y.length)); 180 * numbers.sort((x, y) => x.length.compareTo(y.length));
339 * numbers.join(', '); // 'one, two, four, three' 181 * numbers.join(', '); // 'one, two, four, three'
340 * 182 *
341 * The default List implementations use [Comparable.compare] if 183 * The default List implementations use [Comparable.compare] if
342 * [compare] is omitted. 184 * [compare] is omitted.
343 * 185 *
344 * List<int> nums = [13, 2, -11]; 186 * List<int> nums = [13, 2, -11];
345 * nums.sort(); 187 * nums.sort();
346 nums.join(', '); // '-11, 2, 13' 188 nums.join(', '); // '-11, 2, 13'
347 */ 189 */
348 void sort([int compare(E a, E b)]) { 190 void sort([int compare(E a, E b)]);
349 checkMutable('sort');
350 IterableMixinWorkaround.sortList(this, compare);
351 }
352 191
353 /** 192 /**
354 * Shuffles the elements of this list randomly. 193 * Shuffles the elements of this list randomly.
355 */ 194 */
356 void shuffle([Random random]) { 195 void shuffle([Random random]);
357 IterableMixinWorkaround.shuffleList(this, random);
358 }
359 196
360 /** 197 /**
361 * Returns the first index of [element] in this list. 198 * Returns the first index of [element] in this list.
362 * 199 *
363 * Searches the list from index [start] to the end of the list. 200 * Searches the list from index [start] to the end of the list.
364 * The first time an object [:o:] is encountered so that [:o == element:], 201 * The first time an object [:o:] is encountered so that [:o == element:],
365 * the index of [:o:] is returned. 202 * the index of [:o:] is returned.
366 * 203 *
367 * List<String> notes = ['do', 're', 'mi', 're']; 204 * List<String> notes = ['do', 're', 'mi', 're'];
368 * notes.indexOf('re'); // 1 205 * notes.indexOf('re'); // 1
369 * notes.indexOf('re', 2); // 3 206 * notes.indexOf('re', 2); // 3
370 * 207 *
371 * Returns -1 if [element] is not found. 208 * Returns -1 if [element] is not found.
372 * 209 *
373 * notes.indexOf('fa'); // -1 210 * notes.indexOf('fa'); // -1
374 */ 211 */
375 int indexOf(E element, [int start = 0]) { 212 int indexOf(E element, [int start = 0]);
376 return IterableMixinWorkaround.indexOfList(this, element, start);
377 }
378 213
379 /** 214 /**
380 * Returns the last index of [element] in this list. 215 * Returns the last index of [element] in this list.
381 * 216 *
382 * Searches the list backwards from index [start] to 0. 217 * Searches the list backwards from index [start] to 0.
383 * 218 *
384 * The first time an object [:o:] is encountered so that [:o == element:], 219 * The first time an object [:o:] is encountered so that [:o == element:],
385 * the index of [:o:] is returned. 220 * the index of [:o:] is returned.
386 * 221 *
387 * List<String> notes = ['do', 're', 'mi', 're']; 222 * List<String> notes = ['do', 're', 'mi', 're'];
388 * notes.lastIndexOf('re', 2); // 1 223 * notes.lastIndexOf('re', 2); // 1
389 * 224 *
390 * If [start] is not provided, this method searches from the end of the 225 * If [start] is not provided, this method searches from the end of the
391 * list./Returns 226 * list./Returns
392 * 227 *
393 * notes.lastIndexOf('re'); // 3 228 * notes.lastIndexOf('re'); // 3
394 * 229 *
395 * Returns -1 if [element] is not found. 230 * Returns -1 if [element] is not found.
396 * 231 *
397 * notes.lastIndexOf('fa'); // -1 232 * notes.lastIndexOf('fa'); // -1
398 */ 233 */
399 int lastIndexOf(E element, [int start]) { 234 int lastIndexOf(E element, [int start]);
400 return IterableMixinWorkaround.lastIndexOfList(this, element, start);
401 }
402 235
403 /** 236 /**
404 * Removes all objects from this list; 237 * Removes all objects from this list;
405 * the length of the list becomes zero. 238 * the length of the list becomes zero.
406 * 239 *
407 * Throws an [UnsupportedError], and retains all objects, if this 240 * Throws an [UnsupportedError], and retains all objects, if this
408 * is a fixed-length list. 241 * is a fixed-length list.
409 */ 242 */
410 void clear() { 243 void clear();
411 length = 0;
412 }
413 244
414 /** 245 /**
415 * Inserts the object at position [index] in this list. 246 * Inserts the object at position [index] in this list.
416 * 247 *
417 * This increases the length of the list by one and shifts all objects 248 * This increases the length of the list by one and shifts all objects
418 * at or after the index towards the end of the list. 249 * at or after the index towards the end of the list.
419 * 250 *
420 * An error occurs if the [index] is less than 0 or greater than length. 251 * An error occurs if the [index] is less than 0 or greater than length.
421 * An [UnsupportedError] occurs if the list is fixed-length. 252 * An [UnsupportedError] occurs if the list is fixed-length.
422 */ 253 */
423 void insert(int index, E element) { 254 void insert(int index, E element);
424 if (index is !int) throw new ArgumentError(index);
425 if (index < 0 || index > length) {
426 throw new RangeError.value(index);
427 }
428 checkGrowable('insert');
429 JS('void', r'#.splice(#, 0, #)', this, index, element);
430 }
431
432 255
433 /** 256 /**
434 * Inserts all objects of [iterable] at position [index] in this list. 257 * Inserts all objects of [iterable] at position [index] in this list.
435 * 258 *
436 * This increases the length of the list by the length of [iterable] and 259 * This increases the length of the list by the length of [iterable] and
437 * shifts all later objects towards the end of the list. 260 * shifts all later objects towards the end of the list.
438 * 261 *
439 * An error occurs if the [index] is less than 0 or greater than length. 262 * An error occurs if the [index] is less than 0 or greater than length.
440 * An [UnsupportedError] occurs if the list is fixed-length. 263 * An [UnsupportedError] occurs if the list is fixed-length.
441 */ 264 */
442 void insertAll(int index, Iterable<E> iterable) { 265 void insertAll(int index, Iterable<E> iterable);
443 checkGrowable('insertAll');
444 IterableMixinWorkaround.insertAllList(this, index, iterable);
445 }
446 266
447 /** 267 /**
448 * Overwrites objects of `this` with the objects of [iterable], starting 268 * Overwrites objects of `this` with the objects of [iterable], starting
449 * at position [index] in this list. 269 * at position [index] in this list.
450 * 270 *
451 * List<String> list = ['a', 'b', 'c']; 271 * List<String> list = ['a', 'b', 'c'];
452 * list.setAll(1, ['bee', 'sea']); 272 * list.setAll(1, ['bee', 'sea']);
453 * list.join(', '); // 'a, bee, sea' 273 * list.join(', '); // 'a, bee, sea'
454 * 274 *
455 * This operation does not increase the length of `this`. 275 * This operation does not increase the length of `this`.
456 * 276 *
457 * The [index] must be non-negative and no greater than [length]. 277 * The [index] must be non-negative and no greater than [length].
458 * 278 *
459 * The [iterable] must not have more elements than what can fit from [index] 279 * The [iterable] must not have more elements than what can fit from [index]
460 * to [length]. 280 * to [length].
461 * 281 *
462 * If `iterable` is based on this list, its values may change /during/ the 282 * If `iterable` is based on this list, its values may change /during/ the
463 * `setAll` operation. 283 * `setAll` operation.
464 */ 284 */
465 void setAll(int index, Iterable<E> iterable) { 285 void setAll(int index, Iterable<E> iterable);
466 checkMutable('setAll');
467 IterableMixinWorkaround.setAllList(this, index, iterable);
468 }
469 286
470 /** 287 /**
471 * Removes the first occurence of [value] from this list. 288 * Removes the first occurence of [value] from this list.
472 * 289 *
473 * Returns true if [value] was in the list, false otherwise. 290 * Returns true if [value] was in the list, false otherwise.
474 * 291 *
475 * List<String> parts = ['head', 'shoulders', 'knees', 'toes']; 292 * List<String> parts = ['head', 'shoulders', 'knees', 'toes'];
476 * parts.remove('head'); // true 293 * parts.remove('head'); // true
477 * parts.join(', '); // 'shoulders, knees, toes' 294 * parts.join(', '); // 'shoulders, knees, toes'
478 * 295 *
479 * The method has no effect if [value] was not in the list. 296 * The method has no effect if [value] was not in the list.
480 * 297 *
481 * // Note: 'head' has already been removed. 298 * // Note: 'head' has already been removed.
482 * parts.remove('head'); // false 299 * parts.remove('head'); // false
483 * parts.join(', '); // 'shoulders, knees, toes' 300 * parts.join(', '); // 'shoulders, knees, toes'
484 * 301 *
485 * An [UnsupportedError] occurs if the list is fixed-length. 302 * An [UnsupportedError] occurs if the list is fixed-length.
486 */ 303 */
487 bool remove(Object element) { 304 bool remove(Object value);
488 checkGrowable('remove');
489 for (int i = 0; i < this.length; i++) {
490 if (this[i] == value) {
491 JS('var', r'#.splice(#, 1)', this, i);
492 return true;
493 }
494 }
495 return false;
496 }
497 305
498 /** 306 /**
499 * Removes the object at position [index] from this list. 307 * Removes the object at position [index] from this list.
500 * 308 *
501 * This method reduces the length of `this` by one and moves all later objects 309 * This method reduces the length of `this` by one and moves all later objects
502 * down by one position. 310 * down by one position.
503 * 311 *
504 * Returns the removed object. 312 * Returns the removed object.
505 * 313 *
506 * The [index] must be in the range `0 ≤ index < length`. 314 * The [index] must be in the range `0 ≤ index < length`.
507 * 315 *
508 * Throws an [UnsupportedError] if this is a fixed-length list. In that case 316 * Throws an [UnsupportedError] if this is a fixed-length list. In that case
509 * the list is not modified. 317 * the list is not modified.
510 */ 318 */
511 E removeAt(int index) { 319 E removeAt(int index);
512 if (index is !int) throw new ArgumentError(index);
513 if (index < 0 || index >= length) {
514 throw new RangeError.value(index);
515 }
516 checkGrowable('removeAt');
517 return JS('var', r'#.splice(#, 1)[0]', this, index);
518 }
519 320
520 /** 321 /**
521 * Pops and returns the last object in this list. 322 * Pops and returns the last object in this list.
522 * 323 *
523 * Throws an [UnsupportedError] if this is a fixed-length list. 324 * Throws an [UnsupportedError] if this is a fixed-length list.
524 */ 325 */
525 E removeLast() { 326 E removeLast();
526 checkGrowable('removeLast');
527 if (length == 0) throw new RangeError.value(-1);
528 return JS('var', r'#.pop()', this);
529 }
530 327
531 /** 328 /**
532 * Removes all objects from this list that satisfy [test]. 329 * Removes all objects from this list that satisfy [test].
533 * 330 *
534 * An object [:o:] satisfies [test] if [:test(o):] is true. 331 * An object [:o:] satisfies [test] if [:test(o):] is true.
535 * 332 *
536 * List<String> numbers = ['one', 'two', 'three', 'four']; 333 * List<String> numbers = ['one', 'two', 'three', 'four'];
537 * numbers.removeWhere((item) => item.length == 3); 334 * numbers.removeWhere((item) => item.length == 3);
538 * numbers.join(', '); // 'three, four' 335 * numbers.join(', '); // 'three, four'
539 * 336 *
540 * Throws an [UnsupportedError] if this is a fixed-length list. 337 * Throws an [UnsupportedError] if this is a fixed-length list.
541 */ 338 */
542 void removeWhere(bool test(E element)) { 339 void removeWhere(bool test(E element));
543 // This could, and should, be optimized.
544 IterableMixinWorkaround.removeWhereList(this, test);
545 }
546
547 340
548 /** 341 /**
549 * Removes all objects from this list that fail to satisfy [test]. 342 * Removes all objects from this list that fail to satisfy [test].
550 * 343 *
551 * An object [:o:] satisfies [test] if [:test(o):] is true. 344 * An object [:o:] satisfies [test] if [:test(o):] is true.
552 * 345 *
553 * List<String> numbers = ['one', 'two', 'three', 'four']; 346 * List<String> numbers = ['one', 'two', 'three', 'four'];
554 * numbers.retainWhere((item) => item.length == 3); 347 * numbers.retainWhere((item) => item.length == 3);
555 * numbers.join(', '); // 'one, two' 348 * numbers.join(', '); // 'one, two'
556 * 349 *
557 * Throws an [UnsupportedError] if this is a fixed-length list. 350 * Throws an [UnsupportedError] if this is a fixed-length list.
558 */ 351 */
559 void retainWhere(bool test(E element)) { 352 void retainWhere(bool test(E element));
560 IterableMixinWorkaround.removeWhereList(this,
561 (E element) => !test(element));
562 }
563 353
564 /** 354 /**
565 * Returns a new list containing the objects from [start] inclusive to [end] 355 * Returns a new list containing the objects from [start] inclusive to [end]
566 * exclusive. 356 * exclusive.
567 * 357 *
568 * List<String> colors = ['red', 'green', 'blue', 'orange', 'pink']; 358 * List<String> colors = ['red', 'green', 'blue', 'orange', 'pink'];
569 * colors.sublist(1, 3); // ['green', 'blue'] 359 * colors.sublist(1, 3); // ['green', 'blue']
570 * 360 *
571 * If [end] is omitted, the [length] of `this` is used. 361 * If [end] is omitted, the [length] of `this` is used.
572 * 362 *
573 * colors.sublist(1); // ['green', 'blue', 'orange', 'pink'] 363 * colors.sublist(1); // ['green', 'blue', 'orange', 'pink']
574 * 364 *
575 * An error occurs if [start] is outside the range `0` .. `length` or if 365 * An error occurs if [start] is outside the range `0` .. `length` or if
576 * [end] is outside the range `start` .. `length`. 366 * [end] is outside the range `start` .. `length`.
577 */ 367 */
578 List<E> sublist(int start, [int end]) { 368 List<E> sublist(int start, [int end]);
579 checkNull(start); // TODO(ahe): This is not specified but co19 tests it.
580 if (start is !int) throw new ArgumentError(start);
581 if (start < 0 || start > length) {
582 throw new RangeError.range(start, 0, length);
583 }
584 if (end == null) {
585 end = length;
586 } else {
587 if (end is !int) throw new ArgumentError(end);
588 if (end < start || end > length) {
589 throw new RangeError.range(end, start, length);
590 }
591 }
592 if (start == end) return <E>[];
593 return new JSArray<E>.markGrowable(
594 JS('', r'#.slice(#, #)', this, start, end));
595 }
596 369
597 /** 370 /**
598 * Returns an [Iterable] that iterates over the objects in the range 371 * Returns an [Iterable] that iterates over the objects in the range
599 * [start] inclusive to [end] exclusive. 372 * [start] inclusive to [end] exclusive.
600 * 373 *
601 * An error occurs if [end] is before [start]. 374 * An error occurs if [end] is before [start].
602 * 375 *
603 * An error occurs if the [start] and [end] are not valid ranges at the time 376 * An error occurs if the [start] and [end] are not valid ranges at the time
604 * of the call to this method. The returned [Iterable] behaves like 377 * of the call to this method. The returned [Iterable] behaves like
605 * `skip(start).take(end - start)`. That is, it does not throw exceptions 378 * `skip(start).take(end - start)`. That is, it does not throw exceptions
606 * if `this` changes size. 379 * if `this` changes size.
607 * 380 *
608 * List<String> colors = ['red', 'green', 'blue', 'orange', 'pink']; 381 * List<String> colors = ['red', 'green', 'blue', 'orange', 'pink'];
609 * Iterable<String> range = colors.getRange(1, 4); 382 * Iterable<String> range = colors.getRange(1, 4);
610 * range.join(', '); // 'green, blue, orange' 383 * range.join(', '); // 'green, blue, orange'
611 * colors.length = 3; 384 * colors.length = 3;
612 * range.join(', '); // 'green, blue' 385 * range.join(', '); // 'green, blue'
613 */ 386 */
614 Iterable<E> getRange(int start, int end) { 387 Iterable<E> getRange(int start, int end);
615 return new IterableMixinWorkaround<E>().getRangeList(this, start, end);
616 }
617
618 388
619 /** 389 /**
620 * Copies the objects of [iterable], skipping [skipCount] objects first, 390 * Copies the objects of [iterable], skipping [skipCount] objects first,
621 * into the range [start], inclusive, to [end], exclusive, of the list. 391 * into the range [start], inclusive, to [end], exclusive, of the list.
622 * 392 *
623 * List<int> list1 = [1, 2, 3, 4]; 393 * List<int> list1 = [1, 2, 3, 4];
624 * List<int> list2 = [5, 6, 7, 8, 9]; 394 * List<int> list2 = [5, 6, 7, 8, 9];
625 * // Copies the 4th and 5th items in list2 as the 2nd and 3rd items 395 * // Copies the 4th and 5th items in list2 as the 2nd and 3rd items
626 * // of list1. 396 * // of list1.
627 * list1.setRange(1, 3, list2, 3); 397 * list1.setRange(1, 3, list2, 3);
628 * list1.join(', '); // '1, 8, 9, 4' 398 * list1.join(', '); // '1, 8, 9, 4'
629 * 399 *
630 * The [start] and [end] indices must satisfy `0 ≤ start ≤ end ≤ length`. 400 * The [start] and [end] indices must satisfy `0 ≤ start ≤ end ≤ length`.
631 * If [start] equals [end], this method has no effect. 401 * If [start] equals [end], this method has no effect.
632 * 402 *
633 * The [iterable] must have enough objects to fill the range from `start` 403 * The [iterable] must have enough objects to fill the range from `start`
634 * to `end` after skipping [skipCount] objects. 404 * to `end` after skipping [skipCount] objects.
635 * 405 *
636 * If `iterable` is this list, the operation will copy the elements originally 406 * If `iterable` is this list, the operation will copy the elements originally
637 * in the range from `skipCount` to `skipCount + (end - start)` to the 407 * in the range from `skipCount` to `skipCount + (end - start)` to the
638 * range `start` to `end`, even if the two ranges overlap. 408 * range `start` to `end`, even if the two ranges overlap.
639 * 409 *
640 * If `iterable` depends on this list in some other way, no guarantees are 410 * If `iterable` depends on this list in some other way, no guarantees are
641 * made. 411 * made.
642 */ 412 */
643 void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) { 413 void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]);
644 checkMutable('set range');
645 IterableMixinWorkaround.setRangeList(this, start, end, iterable, skipCount);
646 }
647 414
648 /** 415 /**
649 * Removes the objects in the range [start] inclusive to [end] exclusive. 416 * Removes the objects in the range [start] inclusive to [end] exclusive.
650 * 417 *
651 * The [start] and [end] indices must be in the range 418 * The [start] and [end] indices must be in the range
652 * `0 ≤ index ≤ length`, and `start ≤ end`. 419 * `0 ≤ index ≤ length`, and `start ≤ end`.
653 * 420 *
654 * Throws an [UnsupportedError] if this is a fixed-length list. In that case 421 * Throws an [UnsupportedError] if this is a fixed-length list. In that case
655 * the list is not modified. 422 * the list is not modified.
656 */ 423 */
657 void removeRange(int start, int end) { 424 void removeRange(int start, int end);
658 checkGrowable('removeRange');
659 int receiverLength = this.length;
660 if (start < 0 || start > receiverLength) {
661 throw new RangeError.range(start, 0, receiverLength);
662 }
663 if (end < start || end > receiverLength) {
664 throw new RangeError.range(end, start, receiverLength);
665 }
666 Lists.copy(this,
667 end,
668 this,
669 start,
670 receiverLength - end);
671 this.length = receiverLength - (end - start);
672 }
673 425
674 /** 426 /**
675 * Sets the objects in the range [start] inclusive to [end] exclusive 427 * Sets the objects in the range [start] inclusive to [end] exclusive
676 * to the given [fillValue]. 428 * to the given [fillValue].
677 * 429 *
678 * An error occurs if [start]..[end] is not a valid range for `this`. 430 * An error occurs if [start]..[end] is not a valid range for `this`.
679 */ 431 */
680 void fillRange(int start, int end, [E fillValue]) { 432 void fillRange(int start, int end, [E fillValue]);
681 checkMutable('fill range');
682 IterableMixinWorkaround.fillRangeList(this, start, end, fillValue);
683 }
684 433
685 /** 434 /**
686 * Removes the objects in the range [start] inclusive to [end] exclusive 435 * Removes the objects in the range [start] inclusive to [end] exclusive
687 * and inserts the contents of [replacement] in its place. 436 * and inserts the contents of [replacement] in its place.
688 * 437 *
689 * List<int> list = [1, 2, 3, 4, 5]; 438 * List<int> list = [1, 2, 3, 4, 5];
690 * list.replaceRange(1, 4, [6, 7]); 439 * list.replaceRange(1, 4, [6, 7]);
691 * list.join(', '); // '1, 6, 7, 5' 440 * list.join(', '); // '1, 6, 7, 5'
692 * 441 *
693 * An error occurs if [start]..[end] is not a valid range for `this`. 442 * An error occurs if [start]..[end] is not a valid range for `this`.
443 *
444 * This method does not work on fixed-length lists, even when [replacement]
445 * has the same number of elements as the replaced range. In that case use
446 * [setRange] instead.
694 */ 447 */
695 void replaceRange(int start, int end, Iterable<E> replacement) { 448 void replaceRange(int start, int end, Iterable<E> replacement);
696 checkGrowable('removeRange');
697 IterableMixinWorkaround.replaceRangeList(this, start, end, replacement);
698 }
699 449
700 /** 450 /**
701 * Returns an unmodifiable [Map] view of `this`. 451 * Returns an unmodifiable [Map] view of `this`.
702 * 452 *
703 * The map uses the indices of this list as keys and the corresponding objects 453 * The map uses the indices of this list as keys and the corresponding objects
704 * as values. The `Map.keys` [Iterable] iterates the indices of this list 454 * as values. The `Map.keys` [Iterable] iterates the indices of this list
705 * in numerical order. 455 * in numerical order.
706 * 456 *
707 * List<String> words = ['fee', 'fi', 'fo', 'fum']; 457 * List<String> words = ['fee', 'fi', 'fo', 'fum'];
708 * Map<int, String> map = words.asMap(); 458 * Map<int, String> map = words.asMap();
709 * map[0] + map[1]; // 'feefi'; 459 * map[0] + map[1]; // 'feefi';
710 * map.keys.toList(); // [0, 1, 2, 3] 460 * map.keys.toList(); // [0, 1, 2, 3]
711 */ 461 */
712 Map<int, E> asMap() { 462 Map<int, E> asMap();
713 return new IterableMixinWorkaround<E>().asMapList(this);
714 }
715 } 463 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698