1 | /* |
2 | * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. |
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 | * |
19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
20 | * or visit www.oracle.com if you need additional information or have any |
21 | * questions. |
22 | * |
23 | */ |
24 | |
25 | #ifndef SHARE_UTILITIES_GROWABLEARRAY_HPP |
26 | #define SHARE_UTILITIES_GROWABLEARRAY_HPP |
27 | |
28 | #include "memory/allocation.hpp" |
29 | #include "oops/oop.hpp" |
30 | #include "utilities/debug.hpp" |
31 | #include "utilities/globalDefinitions.hpp" |
32 | #include "utilities/ostream.hpp" |
33 | |
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 { |
80 | friend class VMStructs; |
81 | |
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 |
89 | |
90 | MEMFLAGS _memflags; // memory type if allocation in C heap |
91 | |
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. |
108 | GenericGrowableArray(int initial_size, int initial_len, bool c_heap, MEMFLAGS flags = mtNone) { |
109 | _len = initial_len; |
110 | _max = initial_size; |
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 | |
116 | assert(_len >= 0 && _len <= _max, "initial_len too big" ); |
117 | _arena = (c_heap ? (Arena*)1 : NULL); |
118 | set_nesting(); |
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" ); |
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; |
132 | _memflags = mtNone; |
133 | |
134 | assert(on_arena(), "arena has taken on reserved value 0 or 1" ); |
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" ); |
139 | } |
140 | |
141 | void* raw_allocate(int elementSize); |
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 | } |
148 | |
149 | void free_C_heap(void* elements); |
150 | }; |
151 | |
152 | template<class E> class GrowableArrayIterator; |
153 | template<class E, class UnaryPredicate> class GrowableArrayFilterIterator; |
154 | |
155 | template<class E> |
156 | class CompareClosure : public Closure { |
157 | public: |
158 | virtual int do_compare(const E&, const E&) = 0; |
159 | }; |
160 | |
161 | template<class E> class GrowableArray : public GenericGrowableArray { |
162 | friend class VMStructs; |
163 | |
164 | private: |
165 | E* _data; // data array |
166 | |
167 | void grow(int j); |
168 | void raw_at_put_grow(int i, const E& p, const E& fill); |
169 | void clear_and_deallocate(); |
170 | public: |
171 | GrowableArray(Thread* thread, int initial_size) : GenericGrowableArray(initial_size, 0, false) { |
172 | _data = (E*)raw_allocate(thread, sizeof(E)); |
173 | for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E(); |
174 | } |
175 | |
176 | GrowableArray(int initial_size, bool C_heap = false, MEMFLAGS F = mtInternal) |
177 | : GenericGrowableArray(initial_size, 0, C_heap, F) { |
178 | _data = (E*)raw_allocate(sizeof(E)); |
179 | // Needed for Visual Studio 2012 and older |
180 | #ifdef _MSC_VER |
181 | #pragma warning(suppress: 4345) |
182 | #endif |
183 | for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E(); |
184 | } |
185 | |
186 | GrowableArray(int initial_size, int initial_len, const E& filler, bool C_heap = false, MEMFLAGS memflags = mtInternal) |
187 | : GenericGrowableArray(initial_size, initial_len, C_heap, memflags) { |
188 | _data = (E*)raw_allocate(sizeof(E)); |
189 | int i = 0; |
190 | for (; i < _len; i++) ::new ((void*)&_data[i]) E(filler); |
191 | for (; i < _max; i++) ::new ((void*)&_data[i]) E(); |
192 | } |
193 | |
194 | GrowableArray(Arena* arena, int initial_size, int initial_len, const E& filler) : GenericGrowableArray(arena, initial_size, initial_len) { |
195 | _data = (E*)raw_allocate(sizeof(E)); |
196 | int i = 0; |
197 | for (; i < _len; i++) ::new ((void*)&_data[i]) E(filler); |
198 | for (; i < _max; i++) ::new ((void*)&_data[i]) E(); |
199 | } |
200 | |
201 | GrowableArray() : GenericGrowableArray(2, 0, false) { |
202 | _data = (E*)raw_allocate(sizeof(E)); |
203 | ::new ((void*)&_data[0]) E(); |
204 | ::new ((void*)&_data[1]) E(); |
205 | } |
206 | |
207 | // Does nothing for resource and arena objects |
208 | ~GrowableArray() { if (on_C_heap()) clear_and_deallocate(); } |
209 | |
210 | void clear() { _len = 0; } |
211 | int length() const { return _len; } |
212 | int max_length() const { return _max; } |
213 | void trunc_to(int l) { assert(l <= _len,"cannot increase length" ); _len = l; } |
214 | bool is_empty() const { return _len == 0; } |
215 | bool is_nonempty() const { return _len != 0; } |
216 | bool is_full() const { return _len == _max; } |
217 | DEBUG_ONLY(E* data_addr() const { return _data; }) |
218 | |
219 | void print(); |
220 | |
221 | inline static bool safe_equals(oop obj1, oop obj2) { |
222 | return oopDesc::equals(obj1, obj2); |
223 | } |
224 | |
225 | template <class X> |
226 | inline static bool safe_equals(X i1, X i2) { |
227 | return i1 == i2; |
228 | } |
229 | |
230 | int append(const E& elem) { |
231 | check_nesting(); |
232 | if (_len == _max) grow(_len); |
233 | int idx = _len++; |
234 | _data[idx] = elem; |
235 | return idx; |
236 | } |
237 | |
238 | bool append_if_missing(const E& elem) { |
239 | // Returns TRUE if elem is added. |
240 | bool missed = !contains(elem); |
241 | if (missed) append(elem); |
242 | return missed; |
243 | } |
244 | |
245 | E& at(int i) { |
246 | assert(0 <= i && i < _len, "illegal index" ); |
247 | return _data[i]; |
248 | } |
249 | |
250 | E const& at(int i) const { |
251 | assert(0 <= i && i < _len, "illegal index" ); |
252 | return _data[i]; |
253 | } |
254 | |
255 | E* adr_at(int i) const { |
256 | assert(0 <= i && i < _len, "illegal index" ); |
257 | return &_data[i]; |
258 | } |
259 | |
260 | E first() const { |
261 | assert(_len > 0, "empty list" ); |
262 | return _data[0]; |
263 | } |
264 | |
265 | E top() const { |
266 | assert(_len > 0, "empty list" ); |
267 | return _data[_len-1]; |
268 | } |
269 | |
270 | E last() const { |
271 | return top(); |
272 | } |
273 | |
274 | GrowableArrayIterator<E> begin() const { |
275 | return GrowableArrayIterator<E>(this, 0); |
276 | } |
277 | |
278 | GrowableArrayIterator<E> end() const { |
279 | return GrowableArrayIterator<E>(this, length()); |
280 | } |
281 | |
282 | void push(const E& elem) { append(elem); } |
283 | |
284 | E pop() { |
285 | assert(_len > 0, "empty list" ); |
286 | return _data[--_len]; |
287 | } |
288 | |
289 | void at_put(int i, const E& elem) { |
290 | assert(0 <= i && i < _len, "illegal index" ); |
291 | _data[i] = elem; |
292 | } |
293 | |
294 | E at_grow(int i, const E& fill = E()) { |
295 | assert(0 <= i, "negative index" ); |
296 | check_nesting(); |
297 | if (i >= _len) { |
298 | if (i >= _max) grow(i); |
299 | for (int j = _len; j <= i; j++) |
300 | _data[j] = fill; |
301 | _len = i+1; |
302 | } |
303 | return _data[i]; |
304 | } |
305 | |
306 | void at_put_grow(int i, const E& elem, const E& fill = E()) { |
307 | assert(0 <= i, "negative index" ); |
308 | check_nesting(); |
309 | raw_at_put_grow(i, elem, fill); |
310 | } |
311 | |
312 | bool contains(const E& elem) const { |
313 | for (int i = 0; i < _len; i++) { |
314 | if (safe_equals(_data[i], elem)) return true; |
315 | } |
316 | return false; |
317 | } |
318 | |
319 | int find(const E& elem) const { |
320 | for (int i = 0; i < _len; i++) { |
321 | if (_data[i] == elem) return i; |
322 | } |
323 | return -1; |
324 | } |
325 | |
326 | int find_from_end(const E& elem) const { |
327 | for (int i = _len-1; i >= 0; i--) { |
328 | if (_data[i] == elem) return i; |
329 | } |
330 | return -1; |
331 | } |
332 | |
333 | int find(void* token, bool f(void*, E)) const { |
334 | for (int i = 0; i < _len; i++) { |
335 | if (f(token, _data[i])) return i; |
336 | } |
337 | return -1; |
338 | } |
339 | |
340 | int find_from_end(void* token, bool f(void*, E)) const { |
341 | // start at the end of the array |
342 | for (int i = _len-1; i >= 0; i--) { |
343 | if (f(token, _data[i])) return i; |
344 | } |
345 | return -1; |
346 | } |
347 | |
348 | void remove(const E& elem) { |
349 | for (int i = 0; i < _len; i++) { |
350 | if (_data[i] == elem) { |
351 | for (int j = i + 1; j < _len; j++) _data[j-1] = _data[j]; |
352 | _len--; |
353 | return; |
354 | } |
355 | } |
356 | ShouldNotReachHere(); |
357 | } |
358 | |
359 | // The order is preserved. |
360 | void remove_at(int index) { |
361 | assert(0 <= index && index < _len, "illegal index" ); |
362 | for (int j = index + 1; j < _len; j++) _data[j-1] = _data[j]; |
363 | _len--; |
364 | } |
365 | |
366 | // The order is changed. |
367 | void delete_at(int index) { |
368 | assert(0 <= index && index < _len, "illegal index" ); |
369 | if (index < --_len) { |
370 | // Replace removed element with last one. |
371 | _data[index] = _data[_len]; |
372 | } |
373 | } |
374 | |
375 | // inserts the given element before the element at index i |
376 | void insert_before(const int idx, const E& elem) { |
377 | assert(0 <= idx && idx <= _len, "illegal index" ); |
378 | check_nesting(); |
379 | if (_len == _max) grow(_len); |
380 | for (int j = _len - 1; j >= idx; j--) { |
381 | _data[j + 1] = _data[j]; |
382 | } |
383 | _len++; |
384 | _data[idx] = elem; |
385 | } |
386 | |
387 | void insert_before(const int idx, const GrowableArray<E>* array) { |
388 | assert(0 <= idx && idx <= _len, "illegal index" ); |
389 | check_nesting(); |
390 | int array_len = array->length(); |
391 | int new_len = _len + array_len; |
392 | if (new_len >= _max) grow(new_len); |
393 | |
394 | for (int j = _len - 1; j >= idx; j--) { |
395 | _data[j + array_len] = _data[j]; |
396 | } |
397 | |
398 | for (int j = 0; j < array_len; j++) { |
399 | _data[idx + j] = array->_data[j]; |
400 | } |
401 | |
402 | _len += array_len; |
403 | } |
404 | |
405 | void appendAll(const GrowableArray<E>* l) { |
406 | for (int i = 0; i < l->_len; i++) { |
407 | raw_at_put_grow(_len, l->_data[i], E()); |
408 | } |
409 | } |
410 | |
411 | void sort(int f(E*,E*)) { |
412 | qsort(_data, length(), sizeof(E), (_sort_Fn)f); |
413 | } |
414 | // sort by fixed-stride sub arrays: |
415 | void sort(int f(E*,E*), int stride) { |
416 | qsort(_data, length() / stride, sizeof(E) * stride, (_sort_Fn)f); |
417 | } |
418 | |
419 | // Binary search and insertion utility. Search array for element |
420 | // matching key according to the static compare function. Insert |
421 | // that element is not already in the list. Assumes the list is |
422 | // already sorted according to compare function. |
423 | template <int compare(const E&, const E&)> E insert_sorted(const E& key) { |
424 | bool found; |
425 | int location = find_sorted<E, compare>(key, found); |
426 | if (!found) { |
427 | insert_before(location, key); |
428 | } |
429 | return at(location); |
430 | } |
431 | |
432 | template <typename K, int compare(const K&, const E&)> int find_sorted(const K& key, bool& found) { |
433 | found = false; |
434 | int min = 0; |
435 | int max = length() - 1; |
436 | |
437 | while (max >= min) { |
438 | int mid = (int)(((uint)max + min) / 2); |
439 | E value = at(mid); |
440 | int diff = compare(key, value); |
441 | if (diff > 0) { |
442 | min = mid + 1; |
443 | } else if (diff < 0) { |
444 | max = mid - 1; |
445 | } else { |
446 | found = true; |
447 | return mid; |
448 | } |
449 | } |
450 | return min; |
451 | } |
452 | |
453 | E insert_sorted(CompareClosure<E>* cc, const E& key) { |
454 | bool found; |
455 | int location = find_sorted(cc, key, found); |
456 | if (!found) { |
457 | insert_before(location, key); |
458 | } |
459 | return at(location); |
460 | } |
461 | |
462 | template<typename K> |
463 | int find_sorted(CompareClosure<E>* cc, const K& key, bool& found) { |
464 | found = false; |
465 | int min = 0; |
466 | int max = length() - 1; |
467 | |
468 | while (max >= min) { |
469 | int mid = (int)(((uint)max + min) / 2); |
470 | E value = at(mid); |
471 | int diff = cc->do_compare(key, value); |
472 | if (diff > 0) { |
473 | min = mid + 1; |
474 | } else if (diff < 0) { |
475 | max = mid - 1; |
476 | } else { |
477 | found = true; |
478 | return mid; |
479 | } |
480 | } |
481 | return min; |
482 | } |
483 | }; |
484 | |
485 | // Global GrowableArray methods (one instance in the library per each 'E' type). |
486 | |
487 | template<class E> void GrowableArray<E>::grow(int j) { |
488 | // grow the array by doubling its size (amortized growth) |
489 | int old_max = _max; |
490 | if (_max == 0) _max = 1; // prevent endless loop |
491 | while (j >= _max) _max = _max*2; |
492 | // j < _max |
493 | E* newData = (E*)raw_allocate(sizeof(E)); |
494 | int i = 0; |
495 | for ( ; i < _len; i++) ::new ((void*)&newData[i]) E(_data[i]); |
496 | // Needed for Visual Studio 2012 and older |
497 | #ifdef _MSC_VER |
498 | #pragma warning(suppress: 4345) |
499 | #endif |
500 | for ( ; i < _max; i++) ::new ((void*)&newData[i]) E(); |
501 | for (i = 0; i < old_max; i++) _data[i].~E(); |
502 | if (on_C_heap() && _data != NULL) { |
503 | free_C_heap(_data); |
504 | } |
505 | _data = newData; |
506 | } |
507 | |
508 | template<class E> void GrowableArray<E>::raw_at_put_grow(int i, const E& p, const E& fill) { |
509 | if (i >= _len) { |
510 | if (i >= _max) grow(i); |
511 | for (int j = _len; j < i; j++) |
512 | _data[j] = fill; |
513 | _len = i+1; |
514 | } |
515 | _data[i] = p; |
516 | } |
517 | |
518 | // This function clears and deallocate the data in the growable array that |
519 | // has been allocated on the C heap. It's not public - called by the |
520 | // destructor. |
521 | template<class E> void GrowableArray<E>::clear_and_deallocate() { |
522 | assert(on_C_heap(), |
523 | "clear_and_deallocate should only be called when on C heap" ); |
524 | clear(); |
525 | if (_data != NULL) { |
526 | for (int i = 0; i < _max; i++) _data[i].~E(); |
527 | free_C_heap(_data); |
528 | _data = NULL; |
529 | } |
530 | } |
531 | |
532 | template<class E> void GrowableArray<E>::print() { |
533 | tty->print("Growable Array " INTPTR_FORMAT, this); |
534 | tty->print(": length %ld (_max %ld) { " , _len, _max); |
535 | for (int i = 0; i < _len; i++) tty->print(INTPTR_FORMAT " " , *(intptr_t*)&(_data[i])); |
536 | tty->print("}\n" ); |
537 | } |
538 | |
539 | // Custom STL-style iterator to iterate over GrowableArrays |
540 | // It is constructed by invoking GrowableArray::begin() and GrowableArray::end() |
541 | template<class E> class GrowableArrayIterator : public StackObj { |
542 | friend class GrowableArray<E>; |
543 | template<class F, class UnaryPredicate> friend class GrowableArrayFilterIterator; |
544 | |
545 | private: |
546 | const GrowableArray<E>* _array; // GrowableArray we iterate over |
547 | int _position; // The current position in the GrowableArray |
548 | |
549 | // Private constructor used in GrowableArray::begin() and GrowableArray::end() |
550 | GrowableArrayIterator(const GrowableArray<E>* array, int position) : _array(array), _position(position) { |
551 | assert(0 <= position && position <= _array->length(), "illegal position" ); |
552 | } |
553 | |
554 | public: |
555 | GrowableArrayIterator() : _array(NULL), _position(0) { } |
556 | GrowableArrayIterator<E>& operator++() { ++_position; return *this; } |
557 | E operator*() { return _array->at(_position); } |
558 | |
559 | bool operator==(const GrowableArrayIterator<E>& rhs) { |
560 | assert(_array == rhs._array, "iterator belongs to different array" ); |
561 | return _position == rhs._position; |
562 | } |
563 | |
564 | bool operator!=(const GrowableArrayIterator<E>& rhs) { |
565 | assert(_array == rhs._array, "iterator belongs to different array" ); |
566 | return _position != rhs._position; |
567 | } |
568 | }; |
569 | |
570 | // Custom STL-style iterator to iterate over elements of a GrowableArray that satisfy a given predicate |
571 | template<class E, class UnaryPredicate> class GrowableArrayFilterIterator : public StackObj { |
572 | friend class GrowableArray<E>; |
573 | |
574 | private: |
575 | const GrowableArray<E>* _array; // GrowableArray we iterate over |
576 | int _position; // Current position in the GrowableArray |
577 | UnaryPredicate _predicate; // Unary predicate the elements of the GrowableArray should satisfy |
578 | |
579 | public: |
580 | GrowableArrayFilterIterator(const GrowableArrayIterator<E>& begin, UnaryPredicate filter_predicate) |
581 | : _array(begin._array), _position(begin._position), _predicate(filter_predicate) { |
582 | // Advance to first element satisfying the predicate |
583 | while(_position != _array->length() && !_predicate(_array->at(_position))) { |
584 | ++_position; |
585 | } |
586 | } |
587 | |
588 | GrowableArrayFilterIterator<E, UnaryPredicate>& operator++() { |
589 | do { |
590 | // Advance to next element satisfying the predicate |
591 | ++_position; |
592 | } while(_position != _array->length() && !_predicate(_array->at(_position))); |
593 | return *this; |
594 | } |
595 | |
596 | E operator*() { return _array->at(_position); } |
597 | |
598 | bool operator==(const GrowableArrayIterator<E>& rhs) { |
599 | assert(_array == rhs._array, "iterator belongs to different array" ); |
600 | return _position == rhs._position; |
601 | } |
602 | |
603 | bool operator!=(const GrowableArrayIterator<E>& rhs) { |
604 | assert(_array == rhs._array, "iterator belongs to different array" ); |
605 | return _position != rhs._position; |
606 | } |
607 | |
608 | bool operator==(const GrowableArrayFilterIterator<E, UnaryPredicate>& rhs) { |
609 | assert(_array == rhs._array, "iterator belongs to different array" ); |
610 | return _position == rhs._position; |
611 | } |
612 | |
613 | bool operator!=(const GrowableArrayFilterIterator<E, UnaryPredicate>& rhs) { |
614 | assert(_array == rhs._array, "iterator belongs to different array" ); |
615 | return _position != rhs._position; |
616 | } |
617 | }; |
618 | |
619 | // Arrays for basic types |
620 | typedef GrowableArray<int> intArray; |
621 | typedef GrowableArray<int> intStack; |
622 | typedef GrowableArray<bool> boolArray; |
623 | |
624 | #endif // SHARE_UTILITIES_GROWABLEARRAY_HPP |
625 | |