| 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 _interceptors; | 5 part of _interceptors; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * The interceptor class for [List]. The compiler recognizes this | 8 * The interceptor class for [List]. The compiler recognizes this |
| 9 * class as an interceptor, and changes references to [:this:] to | 9 * class as an interceptor, and changes references to [:this:] to |
| 10 * actually use the receiver of the method, which is generated as an extra | 10 * actually use the receiver of the method, which is generated as an extra |
| 11 * argument added to each member. | 11 * argument added to each member. |
| 12 */ | 12 */ |
| 13 class JSArray<E> extends Interceptor implements List<E>, JSIndexable { | 13 class JSArray<E> extends Interceptor implements List<E>, JSIndexable { |
| 14 | 14 |
| 15 const JSArray(); | 15 const JSArray(); |
| 16 | 16 |
| 17 /** | |
| 18 * Returns a fresh JavaScript Array, marked as fixed-length. | |
| 19 * | |
| 20 * [length] must be a non-negative integer. | |
| 21 */ | |
| 22 factory JSArray.fixed(int length) { | |
| 23 // Explicit type test is necessary to guard against JavaScript conversions | |
| 24 // in unchecked mode. | |
| 25 if ((length is !int) || (length < 0)) { | |
| 26 throw new ArgumentError("Length must be a non-negative integer: $length"); | |
| 27 } | |
| 28 return new JSArray<E>.markFixed(JS('', 'new Array(#)', length)); | |
| 29 } | |
| 30 | |
| 31 /** | |
| 32 * Returns a fresh growable JavaScript Array of zero length length. | |
| 33 */ | |
| 34 factory JSArray.emptyGrowable() => new JSArray<E>.markGrowable(JS('', '[]')); | |
| 35 | |
| 36 /** | |
| 37 * Returns a fresh growable JavaScript Array with initial length. | |
| 38 * | |
| 39 * [validatedLength] must be a non-negative integer. | |
| 40 */ | |
| 41 factory JSArray.growable(int length) { | |
| 42 // Explicit type test is necessary to guard against JavaScript conversions | |
| 43 // in unchecked mode. | |
| 44 if ((length is !int) || (length < 0)) { | |
| 45 throw new ArgumentError("Length must be a non-negative integer: $length"); | |
| 46 } | |
| 47 return new JSArray<E>.markGrowable(JS('', 'new Array(#)', length)); | |
| 48 } | |
| 49 | |
| 50 /** | |
| 51 * Constructor for adding type parameters to an existing JavaScript Array. | |
| 52 * The compiler specially recognizes this constructor. | |
| 53 * | |
| 54 * var a = new JSArray<int>.typed(JS('JSExtendableArray', '[]')); | |
| 55 * a is List<int> --> true | |
| 56 * a is List<String> --> false | |
| 57 * | |
| 58 * Usually either the [JSArray.markFixed] or [JSArray.markGrowable] | |
| 59 * constructors is used instead. | |
| 60 * | |
| 61 * The input must be a JavaScript Array. The JS form is just a re-assertion | |
| 62 * to help type analysis when the input type is sloppy. | |
| 63 */ | |
| 64 factory JSArray.typed(allocation) => JS('JSArray', '#', allocation); | |
| 65 | |
| 66 factory JSArray.markFixed(allocation) => | |
| 67 JS('JSFixedArray', '#', markFixedList(new JSArray<E>.typed(allocation))); | |
| 68 | |
| 69 factory JSArray.markGrowable(allocation) => | |
| 70 JS('JSExtendableArray', '#', new JSArray<E>.typed(allocation)); | |
| 71 | |
| 72 static List markFixedList(List list) { | |
| 73 JS('void', r'#.fixed$length = #', list, true); | |
| 74 return JS('JSFixedArray', '#', list); | |
| 75 } | |
| 76 | |
| 77 checkMutable(reason) { | 17 checkMutable(reason) { |
| 78 if (this is !JSMutableArray) { | 18 if (this is !JSMutableArray) { |
| 79 throw new UnsupportedError(reason); | 19 throw new UnsupportedError(reason); |
| 80 } | 20 } |
| 81 } | 21 } |
| 82 | 22 |
| 83 checkGrowable(reason) { | 23 checkGrowable(reason) { |
| 84 if (this is !JSExtendableArray) { | 24 if (this is !JSExtendableArray) { |
| 85 throw new UnsupportedError(reason); | 25 throw new UnsupportedError(reason); |
| 86 } | 26 } |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 227 throw new RangeError.range(start, 0, length); | 167 throw new RangeError.range(start, 0, length); |
| 228 } | 168 } |
| 229 if (end == null) { | 169 if (end == null) { |
| 230 end = length; | 170 end = length; |
| 231 } else { | 171 } else { |
| 232 if (end is !int) throw new ArgumentError(end); | 172 if (end is !int) throw new ArgumentError(end); |
| 233 if (end < start || end > length) { | 173 if (end < start || end > length) { |
| 234 throw new RangeError.range(end, start, length); | 174 throw new RangeError.range(end, start, length); |
| 235 } | 175 } |
| 236 } | 176 } |
| 237 if (start == end) return <E>[]; | 177 // TODO(ngeoffray): Parameterize the return value. |
| 238 return new JSArray<E>.markGrowable( | 178 if (start == end) return []; |
| 239 JS('', r'#.slice(#, #)', this, start, end)); | 179 return JS('JSExtendableArray', r'#.slice(#, #)', this, start, end); |
| 240 } | 180 } |
| 241 | 181 |
| 242 | 182 |
| 243 Iterable<E> getRange(int start, int end) { | 183 Iterable<E> getRange(int start, int end) { |
| 244 return IterableMixinWorkaround.getRangeList(this, start, end); | 184 return IterableMixinWorkaround.getRangeList(this, start, end); |
| 245 } | 185 } |
| 246 | 186 |
| 247 E get first { | 187 E get first { |
| 248 if (length > 0) return this[0]; | 188 if (length > 0) return this[0]; |
| 249 throw new StateError("No elements"); | 189 throw new StateError("No elements"); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 321 } | 261 } |
| 322 return false; | 262 return false; |
| 323 } | 263 } |
| 324 | 264 |
| 325 bool get isEmpty => length == 0; | 265 bool get isEmpty => length == 0; |
| 326 | 266 |
| 327 bool get isNotEmpty => !isEmpty; | 267 bool get isNotEmpty => !isEmpty; |
| 328 | 268 |
| 329 String toString() => IterableMixinWorkaround.toStringIterable(this, '[', ']'); | 269 String toString() => IterableMixinWorkaround.toStringIterable(this, '[', ']'); |
| 330 | 270 |
| 331 List<E> toList({ bool growable: true }) { | 271 List<E> toList({ bool growable: true }) => |
| 332 if (growable) { | 272 new List<E>.from(this, growable: growable); |
| 333 return new JSArray<E>.markGrowable(JS('', '#.slice()', this)); | |
| 334 } else { | |
| 335 return new JSArray<E>.markFixed(JS('', '#.slice()', this)); | |
| 336 } | |
| 337 } | |
| 338 | 273 |
| 339 Set<E> toSet() => new Set<E>.from(this); | 274 Set<E> toSet() => new Set<E>.from(this); |
| 340 | 275 |
| 341 Iterator<E> get iterator => new ListIterator<E>(this); | 276 Iterator<E> get iterator => new ListIterator<E>(this); |
| 342 | 277 |
| 343 int get hashCode => Primitives.objectHashCode(this); | 278 int get hashCode => Primitives.objectHashCode(this); |
| 344 | 279 |
| 345 int get length => JS('int', r'#.length', this); | 280 int get length => JS('int', r'#.length', this); |
| 346 | 281 |
| 347 void set length(int newLength) { | 282 void set length(int newLength) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 367 Map<int, E> asMap() { | 302 Map<int, E> asMap() { |
| 368 return IterableMixinWorkaround.asMapList(this); | 303 return IterableMixinWorkaround.asMapList(this); |
| 369 } | 304 } |
| 370 } | 305 } |
| 371 | 306 |
| 372 /** | 307 /** |
| 373 * Dummy subclasses that allow the backend to track more precise | 308 * Dummy subclasses that allow the backend to track more precise |
| 374 * information about arrays through their type. The CPA type inference | 309 * information about arrays through their type. The CPA type inference |
| 375 * relies on the fact that these classes do not override [] nor []=. | 310 * relies on the fact that these classes do not override [] nor []=. |
| 376 */ | 311 */ |
| 377 class JSMutableArray<E> extends JSArray<E> implements JSMutableIndexable {} | 312 class JSMutableArray extends JSArray implements JSMutableIndexable {} |
| 378 class JSFixedArray<E> extends JSMutableArray<E> {} | 313 class JSFixedArray extends JSMutableArray {} |
| 379 class JSExtendableArray<E> extends JSMutableArray<E> {} | 314 class JSExtendableArray extends JSMutableArray {} |
| OLD | NEW |