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

Side by Side Diff: runtime/lib/growable_array.dart

Issue 2949803002: New growth strategy for growable arrays (Closed)
Patch Set: Branch-free grow size computation. Renamed function names to be clearer. Created 3 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
« no previous file with comments | « runtime/lib/growable_array.cc ('k') | runtime/lib/stacktrace.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 class _GrowableList<T> extends ListBase<T> { 5 class _GrowableList<T> extends ListBase<T> {
6 void insert(int index, T element) { 6 void insert(int index, T element) {
7 if ((index < 0) || (index > length)) { 7 if ((index < 0) || (index > length)) {
8 throw new RangeError.range(index, 0, length); 8 throw new RangeError.range(index, 0, length);
9 } 9 }
10 if (index == this.length) { 10 if (index == this.length) {
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
80 if (length == 0) return <T>[]; 80 if (length == 0) return <T>[];
81 List list = new _List(length); 81 List list = new _List(length);
82 for (int i = 0; i < length; i++) { 82 for (int i = 0; i < length; i++) {
83 list[i] = this[start + i]; 83 list[i] = this[start + i];
84 } 84 }
85 var result = new _GrowableList<T>.withData(list); 85 var result = new _GrowableList<T>.withData(list);
86 result._setLength(length); 86 result._setLength(length);
87 return result; 87 return result;
88 } 88 }
89 89
90 static const int _kDefaultCapacity = 2;
91
92 factory _GrowableList(int length) { 90 factory _GrowableList(int length) {
93 var data = new _List((length == 0) ? _kDefaultCapacity : length); 91 var data = _allocateData(length);
94 var result = new _GrowableList<T>.withData(data); 92 var result = new _GrowableList<T>.withData(data);
95 if (length > 0) { 93 if (length > 0) {
96 result._setLength(length); 94 result._setLength(length);
97 } 95 }
98 return result; 96 return result;
99 } 97 }
100 98
101 factory _GrowableList.withCapacity(int capacity) { 99 factory _GrowableList.withCapacity(int capacity) {
102 var data = new _List((capacity == 0) ? _kDefaultCapacity : capacity); 100 var data = _allocateData(capacity);
103 return new _GrowableList<T>.withData(data); 101 return new _GrowableList<T>.withData(data);
104 } 102 }
105 103
106 factory _GrowableList.withData(_List data) native "GrowableList_allocate"; 104 factory _GrowableList.withData(_List data) native "GrowableList_allocate";
107 105
108 int get _capacity native "GrowableList_getCapacity"; 106 int get _capacity native "GrowableList_getCapacity";
109 107
110 int get length native "GrowableList_getLength"; 108 int get length native "GrowableList_getLength";
111 109
112 void set length(int new_length) { 110 void set length(int new_length) {
113 int old_capacity = _capacity; 111 int old_capacity = _capacity;
114 int new_capacity = new_length; 112 int new_capacity = new_length;
115 if (new_length == 0) {
116 // Ensure that we use _kDefaultCapacity only when the old_capacity
117 // is greater than _kDefaultCapacity otherwise we end up growing the
118 // the array.
119 if (old_capacity < _kDefaultCapacity) {
120 new_capacity = old_capacity;
121 } else {
122 new_capacity = _kDefaultCapacity;
123 }
124 }
125 if (new_capacity > old_capacity) { 113 if (new_capacity > old_capacity) {
126 _grow(new_capacity); 114 _grow(new_capacity);
127 _setLength(new_length); 115 _setLength(new_length);
128 return; 116 return;
129 } 117 }
130 // We are shrinking. Pick the method which has fewer writes. 118 // We are shrinking. Pick the method which has fewer writes.
131 // In the shrink-to-fit path, we write |new_capacity + new_length| words 119 // In the shrink-to-fit path, we write |new_capacity + new_length| words
132 // (null init + copy). 120 // (null init + copy).
133 // In the non-shrink-to-fit path, we write |length - new_length| words 121 // In the non-shrink-to-fit path, we write |length - new_length| words
134 // (null overwrite). 122 // (null overwrite).
(...skipping 10 matching lines...) Expand all
145 } 133 }
146 134
147 void _setLength(int new_length) native "GrowableList_setLength"; 135 void _setLength(int new_length) native "GrowableList_setLength";
148 136
149 void _setData(_List array) native "GrowableList_setData"; 137 void _setData(_List array) native "GrowableList_setData";
150 138
151 T operator [](int index) native "GrowableList_getIndexed"; 139 T operator [](int index) native "GrowableList_getIndexed";
152 140
153 void operator []=(int index, T value) native "GrowableList_setIndexed"; 141 void operator []=(int index, T value) native "GrowableList_setIndexed";
154 142
155 // The length of this growable array. It is always less than or equal to the
156 // length of the object array, which itself is always greater than 0, so that
157 // grow() does not have to check for a zero length object array before
158 // doubling its size.
159 void add(T value) { 143 void add(T value) {
160 var len = length; 144 var len = length;
161 if (len == _capacity) { 145 if (len == _capacity) {
162 _grow(len * 2); 146 _grow(_nextCapacity(len));
163 } 147 }
164 _setLength(len + 1); 148 _setLength(len + 1);
165 this[len] = value; 149 this[len] = value;
166 } 150 }
167 151
168 void addAll(Iterable<T> iterable) { 152 void addAll(Iterable<T> iterable) {
169 var len = length; 153 var len = length;
170 final cid = ClassID.getID(iterable); 154 final cid = ClassID.getID(iterable);
171 final isVMList = (cid == ClassID.cidArray) || 155 final isVMList = (cid == ClassID.cidArray) ||
172 (cid == ClassID.cidGrowableObjectArray) || 156 (cid == ClassID.cidGrowableObjectArray) ||
173 (cid == ClassID.cidImmutableArray); 157 (cid == ClassID.cidImmutableArray);
174 if (isVMList || (iterable is EfficientLengthIterable)) { 158 if (isVMList || (iterable is EfficientLengthIterable)) {
175 var cap = _capacity; 159 var cap = _capacity;
176 // Pregrow if we know iterable.length. 160 // Pregrow if we know iterable.length.
177 var iterLen = iterable.length; 161 var iterLen = iterable.length;
178 var newLen = len + iterLen; 162 var newLen = len + iterLen;
179 if (newLen > cap) { 163 if (newLen > cap) {
180 do { 164 do {
181 cap *= 2; 165 cap = _nextCapacity(cap);
182 } while (newLen > cap); 166 } while (newLen > cap);
183 _grow(cap); 167 _grow(cap);
184 } 168 }
185 if (isVMList) { 169 if (isVMList) {
186 if (identical(iterable, this)) { 170 if (identical(iterable, this)) {
187 throw new ConcurrentModificationError(this); 171 throw new ConcurrentModificationError(this);
188 } 172 }
189 this._setLength(newLen); 173 this._setLength(newLen);
190 for (int i = 0; i < iterLen; i++) { 174 for (int i = 0; i < iterLen; i++) {
191 this[len++] = iterable[i]; 175 this[len++] = iterable[i];
192 } 176 }
193 return; 177 return;
194 } 178 }
195 } 179 }
196 Iterator it = iterable.iterator; 180 Iterator it = iterable.iterator;
197 if (!it.moveNext()) return; 181 if (!it.moveNext()) return;
198 do { 182 do {
199 while (len < _capacity) { 183 while (len < _capacity) {
200 int newLen = len + 1; 184 int newLen = len + 1;
201 this._setLength(newLen); 185 this._setLength(newLen);
202 this[len] = it.current; 186 this[len] = it.current;
203 if (!it.moveNext()) return; 187 if (!it.moveNext()) return;
204 if (this.length != newLen) throw new ConcurrentModificationError(this); 188 if (this.length != newLen) throw new ConcurrentModificationError(this);
205 len = newLen; 189 len = newLen;
206 } 190 }
207 _grow(_capacity * 2); 191 _grow(_nextCapacity(_capacity));
208 } while (true); 192 } while (true);
209 } 193 }
210 194
211 T removeLast() { 195 T removeLast() {
212 var len = length - 1; 196 var len = length - 1;
213 var elem = this[len]; 197 var elem = this[len];
214 this.length = len; 198 this.length = len;
215 return elem; 199 return elem;
216 } 200 }
217 201
218 T get first { 202 T get first {
219 if (length > 0) return this[0]; 203 if (length > 0) return this[0];
220 throw IterableElementError.noElement(); 204 throw IterableElementError.noElement();
221 } 205 }
222 206
223 T get last { 207 T get last {
224 if (length > 0) return this[length - 1]; 208 if (length > 0) return this[length - 1];
225 throw IterableElementError.noElement(); 209 throw IterableElementError.noElement();
226 } 210 }
227 211
228 T get single { 212 T get single {
229 if (length == 1) return this[0]; 213 if (length == 1) return this[0];
230 if (length == 0) throw IterableElementError.noElement(); 214 if (length == 0) throw IterableElementError.noElement();
231 throw IterableElementError.tooMany(); 215 throw IterableElementError.tooMany();
232 ; 216 ;
233 } 217 }
234 218
219 // Shared array used as backing for new empty growable arrays.
220 static final _List _emptyList = new _List(0);
221
222 static _List _allocateData(int capacity) {
223 if (capacity == 0) {
224 // Use shared empty list as backing.
225 return _emptyList;
226 }
227 // Round up size to the next odd number, since this is free
228 // because of alignment requirements of the GC.
229 return new _List(capacity | 1);
230 }
231
232 // Grow from 0 to 3, and then double + 1.
233 int _nextCapacity(int old_capacity) => (old_capacity * 2) | 3;
234
235 void _grow(int new_capacity) { 235 void _grow(int new_capacity) {
236 var new_data = new _List(new_capacity); 236 var newData = _allocateData(new_capacity);
237 for (int i = 0; i < length; i++) { 237 for (int i = 0; i < length; i++) {
238 new_data[i] = this[i]; 238 newData[i] = this[i];
239 } 239 }
240 _setData(new_data); 240 _setData(newData);
241 } 241 }
242 242
243 void _shrink(int new_capacity, int new_length) { 243 void _shrink(int new_capacity, int new_length) {
244 var new_data = new _List(new_capacity); 244 var newData = _allocateData(new_capacity);
245 for (int i = 0; i < new_length; i++) { 245 for (int i = 0; i < new_length; i++) {
246 new_data[i] = this[i]; 246 newData[i] = this[i];
247 } 247 }
248 _setData(new_data); 248 _setData(newData);
249 } 249 }
250 250
251 // Iterable interface. 251 // Iterable interface.
252 252
253 void forEach(f(T element)) { 253 void forEach(f(T element)) {
254 int initialLength = length; 254 int initialLength = length;
255 for (int i = 0; i < length; i++) { 255 for (int i = 0; i < length; i++) {
256 f(this[i]); 256 f(this[i]);
257 if (length != initialLength) throw new ConcurrentModificationError(this); 257 if (length != initialLength) throw new ConcurrentModificationError(this);
258 } 258 }
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
358 result._setLength(length); 358 result._setLength(length);
359 return result; 359 return result;
360 } 360 }
361 return growable ? <T>[] : new List<T>(0); 361 return growable ? <T>[] : new List<T>(0);
362 } 362 }
363 363
364 Set<T> toSet() { 364 Set<T> toSet() {
365 return new Set<T>.from(this); 365 return new Set<T>.from(this);
366 } 366 }
367 } 367 }
OLDNEW
« no previous file with comments | « runtime/lib/growable_array.cc ('k') | runtime/lib/stacktrace.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698