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 |