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 class GrowableObjectArray<T> implements List<T> { | 5 class GrowableObjectArray<T> implements List<T> { |
| 6 ObjectArray<T> backingArray; | |
| 7 | |
| 8 factory GrowableObjectArray._uninstantiable() { | 6 factory GrowableObjectArray._uninstantiable() { |
| 9 throw const UnsupportedOperationException( | 7 throw const UnsupportedOperationException( |
| 10 "GrowableObjectArray can only be allocated by the VM"); | 8 "GrowableObjectArray can only be allocated by the VM"); |
| 11 } | 9 } |
| 12 | 10 |
| 13 void copyFrom(List<Object> src, int srcStart, int dstStart, int count) { | 11 void copyFrom(List<Object> src, int srcStart, int dstStart, int count) { |
| 14 Arrays.copy(src, srcStart, this, dstStart, count); | 12 Arrays.copy(src, srcStart, this, dstStart, count); |
| 15 } | 13 } |
| 16 | 14 |
| 17 void setRange(int start, int length, List<T> from, [int startFrom = 0]) { | 15 void setRange(int start, int length, List<T> from, [int startFrom = 0]) { |
| 18 if (length < 0) { | 16 if (length < 0) { |
| 19 throw new IllegalArgumentException("negative length $length"); | 17 throw new IllegalArgumentException("negative length $length"); |
| 20 } | 18 } |
| 21 Arrays.copy(from, startFrom, this, start, length); | 19 Arrays.copy(from, startFrom, this, start, length); |
| 22 } | 20 } |
| 23 | 21 |
| 24 void removeRange(int start, int length) { | 22 void removeRange(int start, int length) { |
| 25 if (length == 0) { | 23 if (length == 0) { |
| 26 return; | 24 return; |
| 27 } | 25 } |
| 28 if (length < 0) { | 26 if (length < 0) { |
| 29 throw new IllegalArgumentException("negative length $length"); | 27 throw new IllegalArgumentException("negative length $length"); |
| 30 } | 28 } |
| 31 if (start < 0 || start >= this.length) { | 29 if (start < 0 || start >= this.length) { |
| 32 throw new IndexOutOfRangeException(start); | 30 throw new IndexOutOfRangeException(start); |
| 33 } | 31 } |
| 34 if (start + length > this.length) { | 32 if (start + length > this.length) { |
| 35 throw new IndexOutOfRangeException(start + length); | 33 throw new IndexOutOfRangeException(start + length); |
| 36 } | 34 } |
| 37 Arrays.copy(backingArray, | 35 Arrays.copy(this, |
| 38 start + length, | 36 start + length, |
| 39 backingArray, | 37 this, |
| 40 start, | 38 start, |
| 41 this.length - length - start); | 39 this.length - length - start); |
| 42 this.length = this.length - length; | 40 this.length = this.length - length; |
| 43 } | 41 } |
| 44 | 42 |
| 45 void insertRange(int start, int length, [T initialValue = null]) { | 43 void insertRange(int start, int length, [T initialValue = null]) { |
| 46 if (length == 0) { | 44 if (length == 0) { |
| 47 return; | 45 return; |
| 48 } | 46 } |
| 49 if (length < 0) { | 47 if ((length < 0) || (length is! int)) { |
| 50 throw new IllegalArgumentException("negative length $length"); | 48 throw new IllegalArgumentException("invalid length specified"); |
|
srdjan
2012/04/06 21:19:51
Add $length to message?
siva
2012/04/09 20:57:24
Done.
| |
| 51 } | 49 } |
| 52 if (start < 0 || start > this.length) { | 50 if (start < 0 || start > this.length) { |
| 53 throw new IndexOutOfRangeException(start); | 51 throw new IndexOutOfRangeException(start); |
| 54 } | 52 } |
| 55 if (this.length + length > backingArray.length) { | 53 var old_length = this.length; |
| 56 grow(backingArray.length + length); | 54 this.length = old_length + length; // Will expand if needed. |
| 57 } | 55 Arrays.copy(this, |
| 58 Arrays.copy(backingArray, | |
| 59 start, | 56 start, |
| 60 backingArray, | 57 this, |
| 61 start + length, | 58 start + length, |
| 62 this.length - start); | 59 old_length - start); |
| 63 if (initialValue !== null) { | 60 if (initialValue !== null) { |
| 64 for (int i = start; i < start + length; i++) { | 61 for (int i = start; i < start + length; i++) { |
| 65 backingArray[i] = initialValue; | 62 this[i] = initialValue; |
| 66 } | 63 } |
| 67 } | 64 } |
| 68 this.length = this.length + length; | |
| 69 } | 65 } |
| 70 | 66 |
| 71 List<T> getRange(int start, int length) { | 67 List<T> getRange(int start, int length) { |
| 72 if (length == 0) return []; | 68 if (length == 0) return []; |
| 73 Arrays.rangeCheck(this, start, length); | 69 Arrays.rangeCheck(this, start, length); |
| 74 List list = new List<T>(); | 70 List list = new List<T>(); |
| 75 list.length = length; | 71 list.length = length; |
| 76 Arrays.copy(this, start, list, 0, length); | 72 Arrays.copy(this, start, list, 0, length); |
| 77 return list; | 73 return list; |
| 78 } | 74 } |
| 79 | 75 |
| 80 // The length of this growable array. It is always less than or equal to the | 76 factory GrowableObjectArray() { |
| 81 // length of the backing array, which itself is always greater than 0, so that | 77 var data = new ObjectArray<T>(4); |
| 82 // grow() does not have to check for a zero length backing array before | 78 return new GrowableObjectArray<T>.fromObjectArray(data); |
| 83 // doubling its size. | 79 } |
| 84 int _length; | |
| 85 | 80 |
| 86 GrowableObjectArray() | 81 factory GrowableObjectArray.withCapacity(int capacity) { |
| 87 : _length = 0, backingArray = new ObjectArray<T>(4) {} | 82 var data = new ObjectArray<T>(capacity); |
| 88 | 83 return new GrowableObjectArray<T>.fromObjectArray(data); |
| 89 GrowableObjectArray.withCapacity(int capacity) { | |
| 90 _length = 0; | |
| 91 if (capacity <= 0) { | |
| 92 capacity = 4; | |
| 93 } | |
| 94 backingArray = new ObjectArray<T>(capacity); | |
| 95 } | 84 } |
| 96 | 85 |
| 97 factory GrowableObjectArray.from(Collection<T> other) { | 86 factory GrowableObjectArray.from(Collection<T> other) { |
| 98 List<T> result = new GrowableObjectArray<T>(); | 87 List<T> result = new GrowableObjectArray<T>(); |
| 99 result.addAll(other); | 88 result.addAll(other); |
| 100 return result; | 89 return result; |
| 101 } | 90 } |
| 102 | 91 |
| 103 int get length() { | 92 factory GrowableObjectArray.fromObjectArray(ObjectArray<T> data) |
| 104 return _length; | 93 native "GrowableObjectArray_allocate"; |
| 94 | |
| 95 int get length() native "GrowableObjectArray_getLength"; | |
| 96 | |
| 97 int get capacity() native "GrowableObjectArray_getCapacity"; | |
| 98 | |
| 99 void set length(int new_length) { | |
| 100 if (new_length > capacity) { | |
| 101 _grow(new_length); | |
| 102 } else { | |
| 103 for (int i = new_length; i < length; i++) { | |
| 104 this[i] = null; | |
| 105 } | |
| 106 } | |
| 107 _setLength(new_length); | |
| 105 } | 108 } |
| 106 | 109 |
| 107 void set length(int new_length) { | 110 void _setLength(int new_length) native "GrowableObjectArray_setLength"; |
| 108 if (new_length > backingArray.length) { | 111 |
| 109 grow(new_length); | 112 void set data(ObjectArray<T> array) native "GrowableObjectArray_setData"; |
| 110 } else { | 113 |
| 111 for (int i = new_length; i < _length; i++) { | 114 T operator [](int index) native "GrowableObjectArray_getIndexed"; |
| 112 backingArray[i] = null; | 115 |
| 113 } | 116 void operator []=(int index, T value) native "GrowableObjectArray_setIndexed"; |
| 117 | |
| 118 // The length of this growable array. It is always less than or equal to the | |
| 119 // length of the object array, which itself is always greater than 0, so that | |
| 120 // grow() does not have to check for a zero length object array before | |
| 121 // doubling its size. | |
| 122 void add(T value) { | |
| 123 var len = length; | |
| 124 if (len == capacity) { | |
| 125 _grow(len * 2); | |
| 114 } | 126 } |
| 115 _length = new_length; | 127 _setLength(len + 1); |
| 116 } | 128 this[len] = value; |
| 117 | |
| 118 T operator [](int index) { | |
| 119 if (index is !int) { | |
| 120 throw new IllegalArgumentException("[] with $index"); | |
| 121 } | |
| 122 if (index >= _length) { | |
| 123 throw new IndexOutOfRangeException(index); | |
| 124 } | |
| 125 return backingArray[index]; | |
| 126 } | |
| 127 | |
| 128 void operator []=(int index, T value) { | |
| 129 if (index is !int) { | |
| 130 throw new IllegalArgumentException("[]= with $index"); | |
| 131 } | |
| 132 if (index >= _length) { | |
| 133 throw new IndexOutOfRangeException(index); | |
| 134 } | |
| 135 backingArray[index] = value; | |
| 136 } | |
| 137 | |
| 138 void grow(int capacity) { | |
| 139 ObjectArray<T> newArray = new ObjectArray<T>(capacity); | |
| 140 int length = backingArray.length; | |
| 141 for (int i = 0; i < length; i++) { | |
| 142 newArray[i] = backingArray[i]; | |
| 143 } | |
| 144 backingArray = newArray; | |
| 145 } | |
| 146 | |
| 147 void add(T value) { | |
| 148 if (_length == backingArray.length) { | |
| 149 grow(_length * 2); | |
| 150 } | |
| 151 backingArray[_length] = value; | |
| 152 ++_length; | |
| 153 } | 129 } |
| 154 | 130 |
| 155 void addLast(T element) { | 131 void addLast(T element) { |
| 156 add(element); | 132 add(element); |
| 157 } | 133 } |
| 158 | 134 |
| 159 void addAll(Collection<T> collection) { | 135 void addAll(Collection<T> collection) { |
| 160 for (T elem in collection) { | 136 for (T elem in collection) { |
| 161 add(elem); | 137 add(elem); |
| 162 } | 138 } |
| 163 } | 139 } |
| 164 | 140 |
| 165 T removeLast() { | 141 T removeLast() { |
| 166 if (_length == 0) { | 142 var len = length - 1; |
| 143 if (len < 0) { | |
| 167 throw new IndexOutOfRangeException(-1); | 144 throw new IndexOutOfRangeException(-1); |
| 168 } | 145 } |
| 169 _length--; | 146 var elem = this[len]; |
| 170 return backingArray[_length]; | 147 this[len] = null; |
| 148 _setLength(len); | |
| 149 return elem; | |
| 171 } | 150 } |
| 172 | 151 |
| 173 T last() { | 152 T last() { |
| 174 if (_length === 0) { | 153 if (length === 0) { |
| 175 throw new IndexOutOfRangeException(-1); | 154 throw new IndexOutOfRangeException(-1); |
| 176 } | 155 } |
| 177 return backingArray[_length - 1]; | 156 return this[length - 1]; |
| 178 } | 157 } |
| 179 | 158 |
| 180 int indexOf(T element, [int start = 0]) { | 159 int indexOf(T element, [int start = 0]) { |
| 181 return Arrays.indexOf(backingArray, element, start, _length); | 160 return Arrays.indexOf(this, element, start, length); |
| 182 } | 161 } |
| 183 | 162 |
| 184 int lastIndexOf(T element, [int start = null]) { | 163 int lastIndexOf(T element, [int start = null]) { |
| 185 if (start === null) start = length - 1; | 164 if (start === null) start = length - 1; |
| 186 return Arrays.lastIndexOf(backingArray, element, start); | 165 return Arrays.lastIndexOf(this, element, start); |
| 166 } | |
| 167 | |
| 168 void _grow(int new_length) { | |
| 169 var new_data = new ObjectArray<T>(new_length); | |
| 170 for (int i = 0; i < length; i++) { | |
| 171 new_data[i] = this[i]; | |
| 172 } | |
| 173 data = new_data; | |
| 187 } | 174 } |
| 188 | 175 |
| 189 /** | 176 /** |
| 190 * Collection interface. | 177 * Collection interface. |
| 191 */ | 178 */ |
| 192 | 179 |
| 193 void forEach(f(T element)) { | 180 void forEach(f(T element)) { |
| 194 // TODO(srdjan): Use Collections.forEach(this, f); | 181 // TODO(srdjan): Use Collections.forEach(this, f); |
| 195 // Using backingArray directly improves DeltaBlue performance by 25%. | 182 // Accessing the list directly improves DeltaBlue performance by 25%. |
| 196 for (int i = 0; i < _length; i++) { | 183 for (int i = 0; i < length; i++) { |
| 197 f(backingArray[i]); | 184 f(this[i]); |
| 198 } | 185 } |
| 199 } | 186 } |
| 200 | 187 |
| 201 Collection map(f(T element)) { | 188 Collection map(f(T element)) { |
| 202 return Collections.map(this, new GrowableObjectArray.withCapacity(length), f ); | 189 return Collections.map(this, |
| 190 new GrowableObjectArray.withCapacity(length), f); | |
| 203 } | 191 } |
| 204 | 192 |
| 205 Collection<T> filter(bool f(T element)) { | 193 Collection<T> filter(bool f(T element)) { |
| 206 return Collections.filter(this, new GrowableObjectArray<T>(), f); | 194 return Collections.filter(this, new GrowableObjectArray<T>(), f); |
| 207 } | 195 } |
| 208 | 196 |
| 209 bool every(bool f(T element)) { | 197 bool every(bool f(T element)) { |
| 210 return Collections.every(this, f); | 198 return Collections.every(this, f); |
| 211 } | 199 } |
| 212 | 200 |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 236 } | 224 } |
| 237 | 225 |
| 238 | 226 |
| 239 // Iterator for arrays with variable size. | 227 // Iterator for arrays with variable size. |
| 240 class VariableSizeArrayIterator<T> implements Iterator<T> { | 228 class VariableSizeArrayIterator<T> implements Iterator<T> { |
| 241 VariableSizeArrayIterator(GrowableObjectArray<T> array) | 229 VariableSizeArrayIterator(GrowableObjectArray<T> array) |
| 242 : _array = array, _pos = 0 { | 230 : _array = array, _pos = 0 { |
| 243 } | 231 } |
| 244 | 232 |
| 245 bool hasNext() { | 233 bool hasNext() { |
| 246 return _array._length > _pos; | 234 return _array.length > _pos; |
| 247 } | 235 } |
| 248 | 236 |
| 249 T next() { | 237 T next() { |
| 250 if (!hasNext()) { | 238 if (!hasNext()) { |
| 251 throw const NoMoreElementsException(); | 239 throw const NoMoreElementsException(); |
| 252 } | 240 } |
| 253 return _array[_pos++]; | 241 return _array[_pos++]; |
| 254 } | 242 } |
| 255 | 243 |
| 256 final GrowableObjectArray<T> _array; | 244 final GrowableObjectArray<T> _array; |
| 257 int _pos; | 245 int _pos; |
| 258 } | 246 } |
| 259 | |
| OLD | NEW |