Mercurial > hg > truffle
annotate src/share/vm/utilities/growableArray.hpp @ 20543:e7d0505c8a30
8059758: Footprint regressions with JDK-8038423
Summary: Changes in JDK-8038423 always initialize (zero out) virtual memory used for auxiliary data structures. This causes a footprint regression for G1 in startup benchmarks. This is because they do not touch that memory at all, so the operating system does not actually commit these pages. The fix is to, if the initialization value of the data structures matches the default value of just committed memory (=0), do not do anything.
Reviewed-by: jwilhelm, brutisso
author | tschatzl |
---|---|
date | Fri, 10 Oct 2014 15:51:58 +0200 |
parents | 411e30e5fbb8 |
children | 7848fc12602b |
rev | line source |
---|---|
0 | 1 /* |
17467
55fb97c4c58d
8029233: Update copyright year to match last edit in jdk8 hotspot repository for 2013
mikael
parents:
12080
diff
changeset
|
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. |
0 | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1080
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1080
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1080
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
1972 | 25 #ifndef SHARE_VM_UTILITIES_GROWABLEARRAY_HPP |
26 #define SHARE_VM_UTILITIES_GROWABLEARRAY_HPP | |
27 | |
28 #include "memory/allocation.hpp" | |
29 #include "memory/allocation.inline.hpp" | |
30 #include "utilities/debug.hpp" | |
31 #include "utilities/globalDefinitions.hpp" | |
32 #include "utilities/top.hpp" | |
33 | |
0 | 34 // A growable array. |
35 | |
36 /*************************************************************************/ | |
37 /* */ | |
38 /* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING */ | |
39 /* */ | |
40 /* Should you use GrowableArrays to contain handles you must be certain */ | |
41 /* the the GrowableArray does not outlive the HandleMark that contains */ | |
42 /* the handles. Since GrowableArrays are typically resource allocated */ | |
43 /* the following is an example of INCORRECT CODE, */ | |
44 /* */ | |
45 /* ResourceMark rm; */ | |
46 /* GrowableArray<Handle>* arr = new GrowableArray<Handle>(size); */ | |
47 /* if (blah) { */ | |
48 /* while (...) { */ | |
49 /* HandleMark hm; */ | |
50 /* ... */ | |
51 /* Handle h(THREAD, some_oop); */ | |
52 /* arr->append(h); */ | |
53 /* } */ | |
54 /* } */ | |
55 /* if (arr->length() != 0 ) { */ | |
56 /* oop bad_oop = arr->at(0)(); // Handle is BAD HERE. */ | |
57 /* ... */ | |
58 /* } */ | |
59 /* */ | |
60 /* If the GrowableArrays you are creating is C_Heap allocated then it */ | |
61 /* hould not old handles since the handles could trivially try and */ | |
62 /* outlive their HandleMark. In some situations you might need to do */ | |
63 /* this and it would be legal but be very careful and see if you can do */ | |
64 /* the code in some other manner. */ | |
65 /* */ | |
66 /*************************************************************************/ | |
67 | |
68 // To call default constructor the placement operator new() is used. | |
69 // It should be empty (it only returns the passed void* pointer). | |
70 // The definition of placement operator new(size_t, void*) in the <new>. | |
71 | |
72 #include <new> | |
73 | |
74 // Need the correct linkage to call qsort without warnings | |
75 extern "C" { | |
76 typedef int (*_sort_Fn)(const void *, const void *); | |
77 } | |
78 | |
79 class GenericGrowableArray : public ResourceObj { | |
3939 | 80 friend class VMStructs; |
81 | |
0 | 82 protected: |
83 int _len; // current length | |
84 int _max; // maximum length | |
85 Arena* _arena; // Indicates where allocation occurs: | |
86 // 0 means default ResourceArea | |
87 // 1 means on C heap | |
88 // otherwise, allocate in _arena | |
6197 | 89 |
90 MEMFLAGS _memflags; // memory type if allocation in C heap | |
91 | |
0 | 92 #ifdef ASSERT |
93 int _nesting; // resource area nesting at creation | |
94 void set_nesting(); | |
95 void check_nesting(); | |
96 #else | |
97 #define set_nesting(); | |
98 #define check_nesting(); | |
99 #endif | |
100 | |
101 // Where are we going to allocate memory? | |
102 bool on_C_heap() { return _arena == (Arena*)1; } | |
103 bool on_stack () { return _arena == NULL; } | |
104 bool on_arena () { return _arena > (Arena*)1; } | |
105 | |
106 // This GA will use the resource stack for storage if c_heap==false, | |
107 // Else it will use the C heap. Use clear_and_deallocate to avoid leaks. | |
6197 | 108 GenericGrowableArray(int initial_size, int initial_len, bool c_heap, MEMFLAGS flags = mtNone) { |
0 | 109 _len = initial_len; |
110 _max = initial_size; | |
6197 | 111 _memflags = flags; |
112 | |
113 // memory type has to be specified for C heap allocation | |
114 assert(!(c_heap && flags == mtNone), "memory type not specified for C heap object"); | |
115 | |
0 | 116 assert(_len >= 0 && _len <= _max, "initial_len too big"); |
117 _arena = (c_heap ? (Arena*)1 : NULL); | |
118 set_nesting(); | |
1685 | 119 assert(!on_C_heap() || allocated_on_C_heap(), "growable array must be on C heap if elements are"); |
120 assert(!on_stack() || | |
121 (allocated_on_res_area() || allocated_on_stack()), | |
122 "growable array must be on stack if elements are not on arena and not on C heap"); | |
0 | 123 } |
124 | |
125 // This GA will use the given arena for storage. | |
126 // Consider using new(arena) GrowableArray<T> to allocate the header. | |
127 GenericGrowableArray(Arena* arena, int initial_size, int initial_len) { | |
128 _len = initial_len; | |
129 _max = initial_size; | |
130 assert(_len >= 0 && _len <= _max, "initial_len too big"); | |
131 _arena = arena; | |
6197 | 132 _memflags = mtNone; |
133 | |
0 | 134 assert(on_arena(), "arena has taken on reserved value 0 or 1"); |
1685 | 135 // Relax next assert to allow object allocation on resource area, |
136 // on stack or embedded into an other object. | |
137 assert(allocated_on_arena() || allocated_on_stack(), | |
138 "growable array must be on arena or on stack if elements are on arena"); | |
0 | 139 } |
140 | |
141 void* raw_allocate(int elementSize); | |
432 | 142 |
143 // some uses pass the Thread explicitly for speed (4990299 tuning) | |
144 void* raw_allocate(Thread* thread, int elementSize) { | |
145 assert(on_stack(), "fast ResourceObj path only"); | |
146 return (void*)resource_allocate_bytes(thread, elementSize * _max); | |
147 } | |
0 | 148 }; |
149 | |
20314 | 150 template<class E> class GrowableArrayIterator; |
151 template<class E, class UnaryPredicate> class GrowableArrayFilterIterator; | |
152 | |
0 | 153 template<class E> class GrowableArray : public GenericGrowableArray { |
3939 | 154 friend class VMStructs; |
155 | |
0 | 156 private: |
157 E* _data; // data array | |
158 | |
159 void grow(int j); | |
160 void raw_at_put_grow(int i, const E& p, const E& fill); | |
161 void clear_and_deallocate(); | |
162 public: | |
432 | 163 GrowableArray(Thread* thread, int initial_size) : GenericGrowableArray(initial_size, 0, false) { |
164 _data = (E*)raw_allocate(thread, sizeof(E)); | |
165 for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E(); | |
166 } | |
167 | |
6197 | 168 GrowableArray(int initial_size, bool C_heap = false, MEMFLAGS F = mtInternal) |
169 : GenericGrowableArray(initial_size, 0, C_heap, F) { | |
0 | 170 _data = (E*)raw_allocate(sizeof(E)); |
171 for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E(); | |
172 } | |
173 | |
6197 | 174 GrowableArray(int initial_size, int initial_len, const E& filler, bool C_heap = false, MEMFLAGS memflags = mtInternal) |
175 : GenericGrowableArray(initial_size, initial_len, C_heap, memflags) { | |
0 | 176 _data = (E*)raw_allocate(sizeof(E)); |
177 int i = 0; | |
178 for (; i < _len; i++) ::new ((void*)&_data[i]) E(filler); | |
179 for (; i < _max; i++) ::new ((void*)&_data[i]) E(); | |
180 } | |
181 | |
182 GrowableArray(Arena* arena, int initial_size, int initial_len, const E& filler) : GenericGrowableArray(arena, initial_size, initial_len) { | |
183 _data = (E*)raw_allocate(sizeof(E)); | |
184 int i = 0; | |
185 for (; i < _len; i++) ::new ((void*)&_data[i]) E(filler); | |
186 for (; i < _max; i++) ::new ((void*)&_data[i]) E(); | |
187 } | |
188 | |
189 GrowableArray() : GenericGrowableArray(2, 0, false) { | |
190 _data = (E*)raw_allocate(sizeof(E)); | |
191 ::new ((void*)&_data[0]) E(); | |
192 ::new ((void*)&_data[1]) E(); | |
193 } | |
194 | |
195 // Does nothing for resource and arena objects | |
196 ~GrowableArray() { if (on_C_heap()) clear_and_deallocate(); } | |
197 | |
198 void clear() { _len = 0; } | |
199 int length() const { return _len; } | |
12080 | 200 int max_length() const { return _max; } |
0 | 201 void trunc_to(int l) { assert(l <= _len,"cannot increase length"); _len = l; } |
202 bool is_empty() const { return _len == 0; } | |
203 bool is_nonempty() const { return _len != 0; } | |
204 bool is_full() const { return _len == _max; } | |
205 DEBUG_ONLY(E* data_addr() const { return _data; }) | |
206 | |
207 void print(); | |
208 | |
432 | 209 int append(const E& elem) { |
0 | 210 check_nesting(); |
211 if (_len == _max) grow(_len); | |
432 | 212 int idx = _len++; |
213 _data[idx] = elem; | |
214 return idx; | |
0 | 215 } |
216 | |
5948
ee138854b3a6
7147744: CTW: assert(false) failed: infinite EA connection graph build
kvn
parents:
3939
diff
changeset
|
217 bool append_if_missing(const E& elem) { |
ee138854b3a6
7147744: CTW: assert(false) failed: infinite EA connection graph build
kvn
parents:
3939
diff
changeset
|
218 // Returns TRUE if elem is added. |
ee138854b3a6
7147744: CTW: assert(false) failed: infinite EA connection graph build
kvn
parents:
3939
diff
changeset
|
219 bool missed = !contains(elem); |
ee138854b3a6
7147744: CTW: assert(false) failed: infinite EA connection graph build
kvn
parents:
3939
diff
changeset
|
220 if (missed) append(elem); |
ee138854b3a6
7147744: CTW: assert(false) failed: infinite EA connection graph build
kvn
parents:
3939
diff
changeset
|
221 return missed; |
0 | 222 } |
223 | |
6934 | 224 E& at(int i) { |
225 assert(0 <= i && i < _len, "illegal index"); | |
226 return _data[i]; | |
227 } | |
228 | |
229 E const& at(int i) const { | |
0 | 230 assert(0 <= i && i < _len, "illegal index"); |
231 return _data[i]; | |
232 } | |
233 | |
234 E* adr_at(int i) const { | |
235 assert(0 <= i && i < _len, "illegal index"); | |
236 return &_data[i]; | |
237 } | |
238 | |
239 E first() const { | |
240 assert(_len > 0, "empty list"); | |
241 return _data[0]; | |
242 } | |
243 | |
244 E top() const { | |
245 assert(_len > 0, "empty list"); | |
246 return _data[_len-1]; | |
247 } | |
248 | |
20314 | 249 GrowableArrayIterator<E> begin() const { |
250 return GrowableArrayIterator<E>(this, 0); | |
251 } | |
252 | |
253 GrowableArrayIterator<E> end() const { | |
254 return GrowableArrayIterator<E>(this, length()); | |
255 } | |
256 | |
0 | 257 void push(const E& elem) { append(elem); } |
258 | |
259 E pop() { | |
260 assert(_len > 0, "empty list"); | |
261 return _data[--_len]; | |
262 } | |
263 | |
264 void at_put(int i, const E& elem) { | |
265 assert(0 <= i && i < _len, "illegal index"); | |
266 _data[i] = elem; | |
267 } | |
268 | |
269 E at_grow(int i, const E& fill = E()) { | |
270 assert(0 <= i, "negative index"); | |
271 check_nesting(); | |
272 if (i >= _len) { | |
273 if (i >= _max) grow(i); | |
274 for (int j = _len; j <= i; j++) | |
275 _data[j] = fill; | |
276 _len = i+1; | |
277 } | |
278 return _data[i]; | |
279 } | |
280 | |
281 void at_put_grow(int i, const E& elem, const E& fill = E()) { | |
282 assert(0 <= i, "negative index"); | |
283 check_nesting(); | |
284 raw_at_put_grow(i, elem, fill); | |
285 } | |
286 | |
287 bool contains(const E& elem) const { | |
288 for (int i = 0; i < _len; i++) { | |
289 if (_data[i] == elem) return true; | |
290 } | |
291 return false; | |
292 } | |
293 | |
294 int find(const E& elem) const { | |
295 for (int i = 0; i < _len; i++) { | |
296 if (_data[i] == elem) return i; | |
297 } | |
298 return -1; | |
299 } | |
300 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6197
diff
changeset
|
301 int find_from_end(const E& elem) const { |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6197
diff
changeset
|
302 for (int i = _len-1; i >= 0; i--) { |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6197
diff
changeset
|
303 if (_data[i] == elem) return i; |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6197
diff
changeset
|
304 } |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6197
diff
changeset
|
305 return -1; |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6197
diff
changeset
|
306 } |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6197
diff
changeset
|
307 |
0 | 308 int find(void* token, bool f(void*, E)) const { |
309 for (int i = 0; i < _len; i++) { | |
310 if (f(token, _data[i])) return i; | |
311 } | |
312 return -1; | |
313 } | |
314 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6197
diff
changeset
|
315 int find_from_end(void* token, bool f(void*, E)) const { |
0 | 316 // start at the end of the array |
317 for (int i = _len-1; i >= 0; i--) { | |
318 if (f(token, _data[i])) return i; | |
319 } | |
320 return -1; | |
321 } | |
322 | |
323 void remove(const E& elem) { | |
324 for (int i = 0; i < _len; i++) { | |
325 if (_data[i] == elem) { | |
326 for (int j = i + 1; j < _len; j++) _data[j-1] = _data[j]; | |
327 _len--; | |
328 return; | |
329 } | |
330 } | |
331 ShouldNotReachHere(); | |
332 } | |
333 | |
5948
ee138854b3a6
7147744: CTW: assert(false) failed: infinite EA connection graph build
kvn
parents:
3939
diff
changeset
|
334 // The order is preserved. |
0 | 335 void remove_at(int index) { |
336 assert(0 <= index && index < _len, "illegal index"); | |
337 for (int j = index + 1; j < _len; j++) _data[j-1] = _data[j]; | |
338 _len--; | |
339 } | |
340 | |
5948
ee138854b3a6
7147744: CTW: assert(false) failed: infinite EA connection graph build
kvn
parents:
3939
diff
changeset
|
341 // The order is changed. |
ee138854b3a6
7147744: CTW: assert(false) failed: infinite EA connection graph build
kvn
parents:
3939
diff
changeset
|
342 void delete_at(int index) { |
ee138854b3a6
7147744: CTW: assert(false) failed: infinite EA connection graph build
kvn
parents:
3939
diff
changeset
|
343 assert(0 <= index && index < _len, "illegal index"); |
ee138854b3a6
7147744: CTW: assert(false) failed: infinite EA connection graph build
kvn
parents:
3939
diff
changeset
|
344 if (index < --_len) { |
ee138854b3a6
7147744: CTW: assert(false) failed: infinite EA connection graph build
kvn
parents:
3939
diff
changeset
|
345 // Replace removed element with last one. |
ee138854b3a6
7147744: CTW: assert(false) failed: infinite EA connection graph build
kvn
parents:
3939
diff
changeset
|
346 _data[index] = _data[_len]; |
ee138854b3a6
7147744: CTW: assert(false) failed: infinite EA connection graph build
kvn
parents:
3939
diff
changeset
|
347 } |
ee138854b3a6
7147744: CTW: assert(false) failed: infinite EA connection graph build
kvn
parents:
3939
diff
changeset
|
348 } |
ee138854b3a6
7147744: CTW: assert(false) failed: infinite EA connection graph build
kvn
parents:
3939
diff
changeset
|
349 |
1080
7c57aead6d3e
6892658: C2 should optimize some stringbuilder patterns
never
parents:
470
diff
changeset
|
350 // inserts the given element before the element at index i |
7c57aead6d3e
6892658: C2 should optimize some stringbuilder patterns
never
parents:
470
diff
changeset
|
351 void insert_before(const int idx, const E& elem) { |
20327
411e30e5fbb8
8026796: Make replace_in_map() on parent maps generic
roland
parents:
20314
diff
changeset
|
352 assert(0 <= idx && idx <= _len, "illegal index"); |
1080
7c57aead6d3e
6892658: C2 should optimize some stringbuilder patterns
never
parents:
470
diff
changeset
|
353 check_nesting(); |
7c57aead6d3e
6892658: C2 should optimize some stringbuilder patterns
never
parents:
470
diff
changeset
|
354 if (_len == _max) grow(_len); |
7c57aead6d3e
6892658: C2 should optimize some stringbuilder patterns
never
parents:
470
diff
changeset
|
355 for (int j = _len - 1; j >= idx; j--) { |
7c57aead6d3e
6892658: C2 should optimize some stringbuilder patterns
never
parents:
470
diff
changeset
|
356 _data[j + 1] = _data[j]; |
7c57aead6d3e
6892658: C2 should optimize some stringbuilder patterns
never
parents:
470
diff
changeset
|
357 } |
7c57aead6d3e
6892658: C2 should optimize some stringbuilder patterns
never
parents:
470
diff
changeset
|
358 _len++; |
7c57aead6d3e
6892658: C2 should optimize some stringbuilder patterns
never
parents:
470
diff
changeset
|
359 _data[idx] = elem; |
7c57aead6d3e
6892658: C2 should optimize some stringbuilder patterns
never
parents:
470
diff
changeset
|
360 } |
7c57aead6d3e
6892658: C2 should optimize some stringbuilder patterns
never
parents:
470
diff
changeset
|
361 |
0 | 362 void appendAll(const GrowableArray<E>* l) { |
363 for (int i = 0; i < l->_len; i++) { | |
20327
411e30e5fbb8
8026796: Make replace_in_map() on parent maps generic
roland
parents:
20314
diff
changeset
|
364 raw_at_put_grow(_len, l->_data[i], E()); |
0 | 365 } |
366 } | |
367 | |
368 void sort(int f(E*,E*)) { | |
369 qsort(_data, length(), sizeof(E), (_sort_Fn)f); | |
370 } | |
371 // sort by fixed-stride sub arrays: | |
372 void sort(int f(E*,E*), int stride) { | |
373 qsort(_data, length() / stride, sizeof(E) * stride, (_sort_Fn)f); | |
374 } | |
375 }; | |
376 | |
377 // Global GrowableArray methods (one instance in the library per each 'E' type). | |
378 | |
379 template<class E> void GrowableArray<E>::grow(int j) { | |
380 // grow the array by doubling its size (amortized growth) | |
381 int old_max = _max; | |
382 if (_max == 0) _max = 1; // prevent endless loop | |
383 while (j >= _max) _max = _max*2; | |
384 // j < _max | |
385 E* newData = (E*)raw_allocate(sizeof(E)); | |
386 int i = 0; | |
387 for ( ; i < _len; i++) ::new ((void*)&newData[i]) E(_data[i]); | |
388 for ( ; i < _max; i++) ::new ((void*)&newData[i]) E(); | |
389 for (i = 0; i < old_max; i++) _data[i].~E(); | |
390 if (on_C_heap() && _data != NULL) { | |
391 FreeHeap(_data); | |
392 } | |
393 _data = newData; | |
394 } | |
395 | |
396 template<class E> void GrowableArray<E>::raw_at_put_grow(int i, const E& p, const E& fill) { | |
397 if (i >= _len) { | |
398 if (i >= _max) grow(i); | |
399 for (int j = _len; j < i; j++) | |
400 _data[j] = fill; | |
401 _len = i+1; | |
402 } | |
403 _data[i] = p; | |
404 } | |
405 | |
406 // This function clears and deallocate the data in the growable array that | |
407 // has been allocated on the C heap. It's not public - called by the | |
408 // destructor. | |
409 template<class E> void GrowableArray<E>::clear_and_deallocate() { | |
410 assert(on_C_heap(), | |
411 "clear_and_deallocate should only be called when on C heap"); | |
412 clear(); | |
413 if (_data != NULL) { | |
414 for (int i = 0; i < _max; i++) _data[i].~E(); | |
415 FreeHeap(_data); | |
416 _data = NULL; | |
417 } | |
418 } | |
419 | |
420 template<class E> void GrowableArray<E>::print() { | |
421 tty->print("Growable Array " INTPTR_FORMAT, this); | |
422 tty->print(": length %ld (_max %ld) { ", _len, _max); | |
423 for (int i = 0; i < _len; i++) tty->print(INTPTR_FORMAT " ", *(intptr_t*)&(_data[i])); | |
424 tty->print("}\n"); | |
425 } | |
1972 | 426 |
20314 | 427 // Custom STL-style iterator to iterate over GrowableArrays |
428 // It is constructed by invoking GrowableArray::begin() and GrowableArray::end() | |
429 template<class E> class GrowableArrayIterator : public StackObj { | |
430 friend class GrowableArray<E>; | |
431 template<class F, class UnaryPredicate> friend class GrowableArrayFilterIterator; | |
432 | |
433 private: | |
434 const GrowableArray<E>* _array; // GrowableArray we iterate over | |
435 int _position; // The current position in the GrowableArray | |
436 | |
437 // Private constructor used in GrowableArray::begin() and GrowableArray::end() | |
438 GrowableArrayIterator(const GrowableArray<E>* array, int position) : _array(array), _position(position) { | |
439 assert(0 <= position && position <= _array->length(), "illegal position"); | |
440 } | |
441 | |
442 public: | |
443 GrowableArrayIterator<E>& operator++() { ++_position; return *this; } | |
444 E operator*() { return _array->at(_position); } | |
445 | |
446 bool operator==(const GrowableArrayIterator<E>& rhs) { | |
447 assert(_array == rhs._array, "iterator belongs to different array"); | |
448 return _position == rhs._position; | |
449 } | |
450 | |
451 bool operator!=(const GrowableArrayIterator<E>& rhs) { | |
452 assert(_array == rhs._array, "iterator belongs to different array"); | |
453 return _position != rhs._position; | |
454 } | |
455 }; | |
456 | |
457 // Custom STL-style iterator to iterate over elements of a GrowableArray that satisfy a given predicate | |
458 template<class E, class UnaryPredicate> class GrowableArrayFilterIterator : public StackObj { | |
459 friend class GrowableArray<E>; | |
460 | |
461 private: | |
462 const GrowableArray<E>* _array; // GrowableArray we iterate over | |
463 int _position; // Current position in the GrowableArray | |
464 UnaryPredicate _predicate; // Unary predicate the elements of the GrowableArray should satisfy | |
465 | |
466 public: | |
467 GrowableArrayFilterIterator(const GrowableArrayIterator<E>& begin, UnaryPredicate filter_predicate) | |
468 : _array(begin._array), _position(begin._position), _predicate(filter_predicate) { | |
469 // Advance to first element satisfying the predicate | |
470 while(_position != _array->length() && !_predicate(_array->at(_position))) { | |
471 ++_position; | |
472 } | |
473 } | |
474 | |
475 GrowableArrayFilterIterator<E, UnaryPredicate>& operator++() { | |
476 do { | |
477 // Advance to next element satisfying the predicate | |
478 ++_position; | |
479 } while(_position != _array->length() && !_predicate(_array->at(_position))); | |
480 return *this; | |
481 } | |
482 | |
483 E operator*() { return _array->at(_position); } | |
484 | |
485 bool operator==(const GrowableArrayIterator<E>& rhs) { | |
486 assert(_array == rhs._array, "iterator belongs to different array"); | |
487 return _position == rhs._position; | |
488 } | |
489 | |
490 bool operator!=(const GrowableArrayIterator<E>& rhs) { | |
491 assert(_array == rhs._array, "iterator belongs to different array"); | |
492 return _position != rhs._position; | |
493 } | |
494 | |
495 bool operator==(const GrowableArrayFilterIterator<E, UnaryPredicate>& rhs) { | |
496 assert(_array == rhs._array, "iterator belongs to different array"); | |
497 return _position == rhs._position; | |
498 } | |
499 | |
500 bool operator!=(const GrowableArrayFilterIterator<E, UnaryPredicate>& rhs) { | |
501 assert(_array == rhs._array, "iterator belongs to different array"); | |
502 return _position != rhs._position; | |
503 } | |
504 }; | |
505 | |
1972 | 506 #endif // SHARE_VM_UTILITIES_GROWABLEARRAY_HPP |