1 /*
2 * Copyright (c) 1997, 2020, 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 "memory/iterator.hpp"
30 #include "utilities/debug.hpp"
31 #include "utilities/globalDefinitions.hpp"
32 #include "utilities/ostream.hpp"
33 #include "utilities/powerOfTwo.hpp"
34
35 // A growable array.
36
37 /*************************************************************************/
38 /* */
39 /* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING */
40 /* */
41 /* Should you use GrowableArrays to contain handles you must be certain */
42 /* that the GrowableArray does not outlive the HandleMark that contains */
43 /* the handles. Since GrowableArrays are typically resource allocated */
44 /* the following is an example of INCORRECT CODE, */
45 /* */
46 /* ResourceMark rm; */
47 /* GrowableArray<Handle>* arr = new GrowableArray<Handle>(size); */
48 /* if (blah) { */
49 /* while (...) { */
50 /* HandleMark hm; */
51 /* ... */
52 /* Handle h(THREAD, some_oop); */
53 /* arr->append(h); */
54 /* } */
55 /* } */
56 /* if (arr->length() != 0 ) { */
57 /* oop bad_oop = arr->at(0)(); // Handle is BAD HERE. */
58 /* ... */
59 /* } */
60 /* */
61 /* If the GrowableArrays you are creating is C_Heap allocated then it */
62 /* should not hold handles since the handles could trivially try and */
63 /* outlive their HandleMark. In some situations you might need to do */
64 /* this and it would be legal but be very careful and see if you can do */
65 /* the code in some other manner. */
66 /* */
67 /*************************************************************************/
68
69 // Non-template base class responsible for handling the length and max.
70
71
72 class GrowableArrayBase : public ResourceObj {
73 friend class VMStructs;
74
75 protected:
76 // Current number of accessible elements
77 int _len;
78 // Current number of allocated elements
79 int _max;
80
81 GrowableArrayBase(int initial_max, int initial_len) :
82 _len(initial_len),
83 _max(initial_max) {
84 assert(_len >= 0 && _len <= _max, "initial_len too big");
85 }
86
87 ~GrowableArrayBase() {}
88
89 public:
90 int length() const { return _len; }
91 int max_length() const { return _max; }
92
93 bool is_empty() const { return _len == 0; }
94 bool is_nonempty() const { return _len != 0; }
95 bool is_full() const { return _len == _max; }
96
97 void clear() { _len = 0; }
98 void trunc_to(int length) {
99 assert(length <= _len,"cannot increase length");
100 _len = length;
101 }
102 };
103
104 template <typename E> class GrowableArrayIterator;
105 template <typename E, typename UnaryPredicate> class GrowableArrayFilterIterator;
106
107 // Extends GrowableArrayBase with a typed data array.
108 //
109 // E: Element type
110 //
111 // The "view" adds function that don't grow or deallocate
112 // the _data array, so there's no need for an allocator.
113 //
114 // The "view" can be used to type erase the allocator classes
115 // of GrowableArrayWithAllocator.
116 template <typename E>
117 class GrowableArrayView : public GrowableArrayBase {
118 protected:
119 E* _data; // data array
120
121 GrowableArrayView<E>(E* data, int initial_max, int initial_len) :
122 GrowableArrayBase(initial_max, initial_len), _data(data) {}
123
124 ~GrowableArrayView() {}
125
126 public:
127 E& at(int i) {
128 assert(0 <= i && i < _len, "illegal index");
129 return _data[i];
130 }
131
132 E const& at(int i) const {
133 assert(0 <= i && i < _len, "illegal index");
134 return _data[i];
135 }
136
137 E* adr_at(int i) const {
138 assert(0 <= i && i < _len, "illegal index");
139 return &_data[i];
140 }
141
142 E first() const {
143 assert(_len > 0, "empty list");
144 return _data[0];
145 }
146
147 E top() const {
148 assert(_len > 0, "empty list");
149 return _data[_len-1];
150 }
151
152 E last() const {
153 return top();
154 }
155
156 GrowableArrayIterator<E> begin() const {
157 return GrowableArrayIterator<E>(this, 0);
158 }
159
160 GrowableArrayIterator<E> end() const {
161 return GrowableArrayIterator<E>(this, length());
162 }
163
164 E pop() {
165 assert(_len > 0, "empty list");
166 return _data[--_len];
167 }
168
169 void at_put(int i, const E& elem) {
170 assert(0 <= i && i < _len, "illegal index");
171 _data[i] = elem;
172 }
173
174 bool contains(const E& elem) const {
175 for (int i = 0; i < _len; i++) {
176 if (_data[i] == elem) return true;
177 }
178 return false;
179 }
180
181 int find(const E& elem) const {
182 for (int i = 0; i < _len; i++) {
183 if (_data[i] == elem) return i;
184 }
185 return -1;
186 }
187
188 int find_from_end(const E& elem) const {
189 for (int i = _len-1; i >= 0; i--) {
190 if (_data[i] == elem) return i;
191 }
192 return -1;
193 }
194
195 int find(void* token, bool f(void*, E)) const {
196 for (int i = 0; i < _len; i++) {
197 if (f(token, _data[i])) return i;
198 }
199 return -1;
200 }
201
202 int find_from_end(void* token, bool f(void*, E)) const {
203 // start at the end of the array
204 for (int i = _len-1; i >= 0; i--) {
205 if (f(token, _data[i])) return i;
206 }
207 return -1;
208 }
209
210 // Order preserving remove operations.
211
212 void remove(const E& elem) {
213 // Assuming that element does exist.
214 bool removed = remove_if_existing(elem);
215 if (removed) return;
216 ShouldNotReachHere();
217 }
218
219 bool remove_if_existing(const E& elem) {
220 // Returns TRUE if elem is removed.
221 for (int i = 0; i < _len; i++) {
222 if (_data[i] == elem) {
223 remove_at(i);
224 return true;
225 }
226 }
227 return false;
228 }
229
230 void remove_at(int index) {
231 assert(0 <= index && index < _len, "illegal index");
232 for (int j = index + 1; j < _len; j++) {
233 _data[j-1] = _data[j];
234 }
235 _len--;
236 }
237
238 // The order is changed.
239 void delete_at(int index) {
240 assert(0 <= index && index < _len, "illegal index");
241 if (index < --_len) {
242 // Replace removed element with last one.
243 _data[index] = _data[_len];
244 }
245 }
246
247 void sort(int f(E*, E*)) {
248 qsort(_data, length(), sizeof(E), (_sort_Fn)f);
249 }
250 // sort by fixed-stride sub arrays:
251 void sort(int f(E*, E*), int stride) {
252 qsort(_data, length() / stride, sizeof(E) * stride, (_sort_Fn)f);
253 }
254
255 template <typename K, int compare(const K&, const E&)> int find_sorted(const K& key, bool& found) {
256 found = false;
257 int min = 0;
258 int max = length() - 1;
259
260 while (max >= min) {
261 int mid = (int)(((uint)max + min) / 2);
262 E value = at(mid);
263 int diff = compare(key, value);
264 if (diff > 0) {
265 min = mid + 1;
266 } else if (diff < 0) {
267 max = mid - 1;
268 } else {
269 found = true;
270 return mid;
271 }
272 }
273 return min;
274 }
275
276 template <typename K>
277 int find_sorted(CompareClosure<E>* cc, const K& key, bool& found) {
278 found = false;
279 int min = 0;
280 int max = length() - 1;
281
282 while (max >= min) {
283 int mid = (int)(((uint)max + min) / 2);
284 E value = at(mid);
285 int diff = cc->do_compare(key, value);
286 if (diff > 0) {
287 min = mid + 1;
288 } else if (diff < 0) {
289 max = mid - 1;
290 } else {
291 found = true;
292 return mid;
293 }
294 }
295 return min;
296 }
297
298 void print() {
299 tty->print("Growable Array " INTPTR_FORMAT, this);
300 tty->print(": length %ld (_max %ld) { ", _len, _max);
301 for (int i = 0; i < _len; i++) {
302 tty->print(INTPTR_FORMAT " ", *(intptr_t*)&(_data[i]));
303 }
304 tty->print("}\n");
305 }
306 };
307
308 // GrowableArrayWithAllocator extends the "view" with
309 // the capability to grow and deallocate the data array.
310 //
311 // The allocator responsibility is delegated to the sub-class.
312 //
313 // Derived: The sub-class responsible for allocation / deallocation
314 // - E* Derived::allocate() - member function responsible for allocation
315 // - void Derived::deallocate(E*) - member function responsible for deallocation
316 template <typename E, typename Derived>
317 class GrowableArrayWithAllocator : public GrowableArrayView<E> {
318 friend class VMStructs;
319
320 void grow(int j);
321
322 protected:
323 GrowableArrayWithAllocator(E* data, int initial_max) :
324 GrowableArrayView<E>(data, initial_max, 0) {
325 for (int i = 0; i < initial_max; i++) {
326 ::new ((void*)&data[i]) E();
327 }
328 }
329
330 GrowableArrayWithAllocator(E* data, int initial_max, int initial_len, const E& filler) :
331 GrowableArrayView<E>(data, initial_max, initial_len) {
332 int i = 0;
333 for (; i < initial_len; i++) {
334 ::new ((void*)&data[i]) E(filler);
335 }
336 for (; i < initial_max; i++) {
337 ::new ((void*)&data[i]) E();
338 }
339 }
340
341 ~GrowableArrayWithAllocator() {}
342
343 public:
344 int append(const E& elem) {
345 if (this->_len == this->_max) grow(this->_len);
346 int idx = this->_len++;
347 this->_data[idx] = elem;
348 return idx;
349 }
350
351 bool append_if_missing(const E& elem) {
352 // Returns TRUE if elem is added.
353 bool missed = !this->contains(elem);
354 if (missed) append(elem);
355 return missed;
356 }
357
358 void push(const E& elem) { append(elem); }
359
360 E at_grow(int i, const E& fill = E()) {
361 assert(0 <= i, "negative index");
362 if (i >= this->_len) {
363 if (i >= this->_max) grow(i);
364 for (int j = this->_len; j <= i; j++)
365 this->_data[j] = fill;
366 this->_len = i+1;
367 }
368 return this->_data[i];
369 }
370
371 void at_put_grow(int i, const E& elem, const E& fill = E()) {
372 assert(0 <= i, "negative index");
373 if (i >= this->_len) {
374 if (i >= this->_max) grow(i);
375 for (int j = this->_len; j < i; j++)
376 this->_data[j] = fill;
377 this->_len = i+1;
378 }
379 this->_data[i] = elem;
380 }
381
382 // inserts the given element before the element at index i
383 void insert_before(const int idx, const E& elem) {
384 assert(0 <= idx && idx <= this->_len, "illegal index");
385 if (this->_len == this->_max) grow(this->_len);
386 for (int j = this->_len - 1; j >= idx; j--) {
387 this->_data[j + 1] = this->_data[j];
388 }
389 this->_len++;
390 this->_data[idx] = elem;
391 }
392
393 void insert_before(const int idx, const GrowableArrayView<E>* array) {
394 assert(0 <= idx && idx <= this->_len, "illegal index");
395 int array_len = array->length();
396 int new_len = this->_len + array_len;
397 if (new_len >= this->_max) grow(new_len);
398
399 for (int j = this->_len - 1; j >= idx; j--) {
400 this->_data[j + array_len] = this->_data[j];
401 }
402
403 for (int j = 0; j < array_len; j++) {
404 this->_data[idx + j] = array->at(j);
405 }
406
407 this->_len += array_len;
408 }
409
410 void appendAll(const GrowableArrayView<E>* l) {
411 for (int i = 0; i < l->length(); i++) {
412 this->at_put_grow(this->_len, l->at(i), E());
413 }
414 }
415
416 // Binary search and insertion utility. Search array for element
417 // matching key according to the static compare function. Insert
418 // that element is not already in the list. Assumes the list is
419 // already sorted according to compare function.
420 template <int compare(const E&, const E&)> E insert_sorted(const E& key) {
421 bool found;
422 int location = GrowableArrayView<E>::template find_sorted<E, compare>(key, found);
423 if (!found) {
424 insert_before(location, key);
425 }
426 return this->at(location);
427 }
428
429 E insert_sorted(CompareClosure<E>* cc, const E& key) {
430 bool found;
431 int location = find_sorted(cc, key, found);
432 if (!found) {
433 insert_before(location, key);
434 }
435 return this->at(location);
436 }
437
438 void clear_and_deallocate();
439 };
440
441 template <typename E, typename Derived>
442 void GrowableArrayWithAllocator<E, Derived>::grow(int j) {
443 int old_max = this->_max;
444 // grow the array by increasing _max to the first power of two larger than the size we need
445 this->_max = next_power_of_2((uint32_t)j);
446 // j < _max
447 E* newData = static_cast<Derived*>(this)->allocate();
448 int i = 0;
449 for ( ; i < this->_len; i++) ::new ((void*)&newData[i]) E(this->_data[i]);
450 for ( ; i < this->_max; i++) ::new ((void*)&newData[i]) E();
451 for (i = 0; i < old_max; i++) this->_data[i].~E();
452 if (this->_data != NULL) {
453 static_cast<Derived*>(this)->deallocate(this->_data);
454 }
455 this->_data = newData;
456 }
457
458 template <typename E, typename Derived>
459 void GrowableArrayWithAllocator<E, Derived>::clear_and_deallocate() {
460 if (this->_data != NULL) {
461 for (int i = 0; i < this->_max; i++) {
462 this->_data[i].~E();
463 }
464 static_cast<Derived*>(this)->deallocate(this->_data);
465 this->_data = NULL;
466 }
467 this->_len = 0;
468 this->_max = 0;
469 }
470
471 class GrowableArrayResourceAllocator {
472 public:
473 static void* allocate(int max, int element_size);
474 };
475
476 // Arena allocator
477 class GrowableArrayArenaAllocator {
478 public:
479 static void* allocate(int max, int element_size, Arena* arena);
480 };
481
482 // CHeap allocator
483 class GrowableArrayCHeapAllocator {
484 public:
485 static void* allocate(int max, int element_size, MEMFLAGS memflags);
486 static void deallocate(void* mem);
487 };
488
489 #ifdef ASSERT
490
491 // Checks resource allocation nesting
492 class GrowableArrayNestingCheck {
493 // resource area nesting at creation
494 int _nesting;
495
496 public:
497 GrowableArrayNestingCheck(bool on_stack);
498
499 void on_stack_alloc() const;
500 };
501
502 #endif // ASSERT
503
504 // Encodes where the backing array is allocated
505 // and performs necessary checks.
506 class GrowableArrayMetadata {
507 uintptr_t _bits;
508
509 // resource area nesting at creation
510 debug_only(GrowableArrayNestingCheck _nesting_check;)
511
512 uintptr_t bits(MEMFLAGS memflags) const {
513 if (memflags == mtNone) {
514 // Stack allocation
515 return 0;
516 }
517
518 // CHeap allocation
519 return (uintptr_t(memflags) << 1) | 1;
520 }
521
522 uintptr_t bits(Arena* arena) const {
523 return uintptr_t(arena);
524 }
525
526 public:
527 GrowableArrayMetadata(Arena* arena) :
528 _bits(bits(arena))
529 debug_only(COMMA _nesting_check(on_stack())) {
530 }
531
532 GrowableArrayMetadata(MEMFLAGS memflags) :
533 _bits(bits(memflags))
534 debug_only(COMMA _nesting_check(on_stack())) {
535 }
536
537 #ifdef ASSERT
538 GrowableArrayMetadata(const GrowableArrayMetadata& other) :
539 _bits(other._bits),
540 _nesting_check(other._nesting_check) {
541 assert(!on_C_heap(), "Copying of CHeap arrays not supported");
542 assert(!other.on_C_heap(), "Copying of CHeap arrays not supported");
543 }
544
545 GrowableArrayMetadata& operator=(const GrowableArrayMetadata& other) {
546 _bits = other._bits;
547 _nesting_check = other._nesting_check;
548 assert(!on_C_heap(), "Assignment of CHeap arrays not supported");
549 assert(!other.on_C_heap(), "Assignment of CHeap arrays not supported");
550 return *this;
551 }
552
553 void init_checks(const GrowableArrayBase* array) const;
554 void on_stack_alloc_check() const;
555 #endif // ASSERT
556
557 bool on_C_heap() const { return (_bits & 1) == 1; }
558 bool on_stack () const { return _bits == 0; }
559 bool on_arena () const { return (_bits & 1) == 0 && _bits != 0; }
560
561 Arena* arena() const { return (Arena*)_bits; }
562 MEMFLAGS memflags() const { return MEMFLAGS(_bits >> 1); }
563 };
564
565 // THE GrowableArray.
566 //
567 // Supports multiple allocation strategies:
568 // - Resource stack allocation: if memflags == mtNone
569 // - CHeap allocation: if memflags != mtNone
570 // - Arena allocation: if an arena is provided
571 //
572 // There are some drawbacks of using GrowableArray, that are removed in some
573 // of the other implementations of GrowableArrayWithAllocator sub-classes:
574 //
575 // Memory overhead: The multiple allocation strategies uses extra metadata
576 // embedded in the instance.
577 //
578 // Strict allocation locations: There are rules about where the GrowableArray
579 // instance is allocated, that depends on where the data array is allocated.
580 // See: init_checks.
581
582 template <typename E>
583 class GrowableArray : public GrowableArrayWithAllocator<E, GrowableArray<E> > {
584 friend class GrowableArrayWithAllocator<E, GrowableArray<E> >;
585 friend class GrowableArrayTest;
586
587 static E* allocate(int max) {
588 return (E*)GrowableArrayResourceAllocator::allocate(max, sizeof(E));
589 }
590
591 static E* allocate(int max, MEMFLAGS memflags) {
592 if (memflags != mtNone) {
593 return (E*)GrowableArrayCHeapAllocator::allocate(max, sizeof(E), memflags);
594 }
595
596 return (E*)GrowableArrayResourceAllocator::allocate(max, sizeof(E));
597 }
598
599 static E* allocate(int max, Arena* arena) {
600 return (E*)GrowableArrayArenaAllocator::allocate(max, sizeof(E), arena);
601 }
602
603 GrowableArrayMetadata _metadata;
604
605 void init_checks() const { debug_only(_metadata.init_checks(this);) }
606
607 // Where are we going to allocate memory?
608 bool on_C_heap() const { return _metadata.on_C_heap(); }
609 bool on_stack () const { return _metadata.on_stack(); }
610 bool on_arena () const { return _metadata.on_arena(); }
611
612 E* allocate() {
613 if (on_stack()) {
614 debug_only(_metadata.on_stack_alloc_check());
615 return allocate(this->_max);
616 }
617
618 if (on_C_heap()) {
619 return allocate(this->_max, _metadata.memflags());
620 }
621
622 assert(on_arena(), "Sanity");
623 return allocate(this->_max, _metadata.arena());
624 }
625
626 void deallocate(E* mem) {
627 if (on_C_heap()) {
628 GrowableArrayCHeapAllocator::deallocate(mem);
629 }
630 }
631
632 public:
633 GrowableArray(int initial_max = 2, MEMFLAGS memflags = mtNone) :
634 GrowableArrayWithAllocator<E, GrowableArray<E> >(
635 allocate(initial_max, memflags),
636 initial_max),
637 _metadata(memflags) {
638 init_checks();
639 }
640
641 GrowableArray(int initial_max, int initial_len, const E& filler, MEMFLAGS memflags = mtNone) :
642 GrowableArrayWithAllocator<E, GrowableArray<E> >(
643 allocate(initial_max, memflags),
644 initial_max, initial_len, filler),
645 _metadata(memflags) {
646 init_checks();
647 }
648
649 GrowableArray(Arena* arena, int initial_max, int initial_len, const E& filler) :
650 GrowableArrayWithAllocator<E, GrowableArray<E> >(
651 allocate(initial_max, arena),
652 initial_max, initial_len, filler),
653 _metadata(arena) {
654 init_checks();
655 }
656
657 ~GrowableArray() {
658 if (on_C_heap()) {
659 this->clear_and_deallocate();
660 }
661 }
662 };
663
664 // Leaner GrowableArray for CHeap backed data arrays, with compile-time decided MEMFLAGS.
665 template <typename E, MEMFLAGS F>
666 class GrowableArrayCHeap : public GrowableArrayWithAllocator<E, GrowableArrayCHeap<E, F> > {
667 friend class GrowableArrayWithAllocator<E, GrowableArrayCHeap<E, F> >;
668
669 STATIC_ASSERT(F != mtNone);
670
671 static E* allocate(int max, MEMFLAGS flags) {
672 if (max == 0) {
673 return NULL;
674 }
675
676 return (E*)GrowableArrayCHeapAllocator::allocate(max, sizeof(E), flags);
677 }
678
679 NONCOPYABLE(GrowableArrayCHeap);
680
681 E* allocate() {
682 return allocate(this->_max, F);
683 }
684
685 void deallocate(E* mem) {
686 GrowableArrayCHeapAllocator::deallocate(mem);
687 }
688
689 public:
690 GrowableArrayCHeap(int initial_max) :
691 GrowableArrayWithAllocator<E, GrowableArrayCHeap<E, F> >(
692 allocate(initial_max, F),
693 initial_max) {}
694
695 GrowableArrayCHeap(int initial_max, int initial_len, const E& filler) :
696 GrowableArrayWithAllocator<E, GrowableArrayCHeap<E, F> >(
697 allocate(initial_max, F),
698 initial_max, initial_len, filler) {}
699
700 ~GrowableArrayCHeap() {
701 this->clear_and_deallocate();
702 }
703
704 void* operator new(size_t size) throw() {
705 return ResourceObj::operator new(size, ResourceObj::C_HEAP, F);
706 }
707
708 void* operator new(size_t size, const std::nothrow_t& nothrow_constant) throw() {
709 return ResourceObj::operator new(size, nothrow_constant, ResourceObj::C_HEAP, F);
710 }
711 };
712
713 // Custom STL-style iterator to iterate over GrowableArrays
714 // It is constructed by invoking GrowableArray::begin() and GrowableArray::end()
715 template <typename E>
716 class GrowableArrayIterator : public StackObj {
717 friend class GrowableArrayView<E>;
718 template <typename F, typename UnaryPredicate> friend class GrowableArrayFilterIterator;
719
720 private:
721 const GrowableArrayView<E>* _array; // GrowableArray we iterate over
722 int _position; // The current position in the GrowableArray
723
724 // Private constructor used in GrowableArray::begin() and GrowableArray::end()
725 GrowableArrayIterator(const GrowableArrayView<E>* array, int position) : _array(array), _position(position) {
726 assert(0 <= position && position <= _array->length(), "illegal position");
727 }
728
729 public:
730 GrowableArrayIterator() : _array(NULL), _position(0) { }
731 GrowableArrayIterator<E>& operator++() { ++_position; return *this; }
732 E operator*() { return _array->at(_position); }
733
734 bool operator==(const GrowableArrayIterator<E>& rhs) {
735 assert(_array == rhs._array, "iterator belongs to different array");
736 return _position == rhs._position;
737 }
738
739 bool operator!=(const GrowableArrayIterator<E>& rhs) {
740 assert(_array == rhs._array, "iterator belongs to different array");
741 return _position != rhs._position;
742 }
743 };
744
745 // Custom STL-style iterator to iterate over elements of a GrowableArray that satisfy a given predicate
746 template <typename E, class UnaryPredicate>
747 class GrowableArrayFilterIterator : public StackObj {
748 friend class GrowableArrayView<E>;
749
750 private:
751 const GrowableArrayView<E>* _array; // GrowableArray we iterate over
752 int _position; // Current position in the GrowableArray
753 UnaryPredicate _predicate; // Unary predicate the elements of the GrowableArray should satisfy
754
755 public:
756 GrowableArrayFilterIterator(const GrowableArrayIterator<E>& begin, UnaryPredicate filter_predicate) :
757 _array(begin._array), _position(begin._position), _predicate(filter_predicate) {
758 // Advance to first element satisfying the predicate
759 while(_position != _array->length() && !_predicate(_array->at(_position))) {
760 ++_position;
761 }
762 }
763
764 GrowableArrayFilterIterator<E, UnaryPredicate>& operator++() {
765 do {
766 // Advance to next element satisfying the predicate
767 ++_position;
768 } while(_position != _array->length() && !_predicate(_array->at(_position)));
769 return *this;
770 }
771
772 E operator*() { return _array->at(_position); }
773
774 bool operator==(const GrowableArrayIterator<E>& rhs) {
775 assert(_array == rhs._array, "iterator belongs to different array");
776 return _position == rhs._position;
777 }
778
779 bool operator!=(const GrowableArrayIterator<E>& rhs) {
780 assert(_array == rhs._array, "iterator belongs to different array");
781 return _position != rhs._position;
782 }
783
784 bool operator==(const GrowableArrayFilterIterator<E, UnaryPredicate>& rhs) {
785 assert(_array == rhs._array, "iterator belongs to different array");
786 return _position == rhs._position;
787 }
788
789 bool operator!=(const GrowableArrayFilterIterator<E, UnaryPredicate>& rhs) {
790 assert(_array == rhs._array, "iterator belongs to different array");
791 return _position != rhs._position;
792 }
793 };
794
795 // Arrays for basic types
796 typedef GrowableArray<int> intArray;
797 typedef GrowableArray<int> intStack;
798 typedef GrowableArray<bool> boolArray;
799
800 #endif // SHARE_UTILITIES_GROWABLEARRAY_HPP