/* * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
/*************************************************************************/ /* */ /* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING */ /* */ /* Should you use GrowableArrays to contain handles you must be certain */ /* that the GrowableArray does not outlive the HandleMark that contains */ /* the handles. Since GrowableArrays are typically resource allocated */ /* the following is an example of INCORRECT CODE, */ /* */ /* ResourceMark rm; */ /* GrowableArray<Handle>* arr = new GrowableArray<Handle>(size); */ /* if (blah) { */ /* while (...) { */ /* HandleMark hm; */ /* ... */ /* Handle h(THREAD, some_oop); */ /* arr->append(h); */ /* } */ /* } */ /* if (arr->length() != 0 ) { */ /* oop bad_oop = arr->at(0)(); // Handle is BAD HERE. */ /* ... */ /* } */ /* */ /* If the GrowableArrays you are creating is C_Heap allocated then it */ /* should not hold handles since the handles could trivially try and */ /* outlive their HandleMark. In some situations you might need to do */ /* this and it would be legal but be very careful and see if you can do */ /* the code in some other manner. */ /* */ /*************************************************************************/
// Non-template base class responsible for handling the length and max.
class GrowableArrayBase : public AnyObj { friendclass VMStructs;
protected: // Current number of accessible elements int _len; // Current number of allocated elements int _capacity;
GrowableArrayBase(int capacity, int initial_len) :
_len(initial_len),
_capacity(capacity) {
assert(_len >= 0 && _len <= _capacity, "initial_len too big");
}
~GrowableArrayBase() {}
public: int length() const { return _len; } int capacity() const { return _capacity; }
template <typename E> class GrowableArrayIterator; template <typename E, typename UnaryPredicate> class GrowableArrayFilterIterator;
// Extends GrowableArrayBase with a typed data array. // // E: Element type // // The "view" adds function that don't grow or deallocate // the _data array, so there's no need for an allocator. // // The "view" can be used to type erase the allocator classes // of GrowableArrayWithAllocator. template <typename E> class GrowableArrayView : public GrowableArrayBase { protected:
E* _data; // data array
GrowableArrayView<E>(E* data, int capacity, int initial_len) :
GrowableArrayBase(capacity, initial_len), _data(data) {}
~GrowableArrayView() {}
public: conststatic GrowableArrayView EMPTY;
booloperator==(const GrowableArrayView<E>& rhs) const { if (_len != rhs._len) returnfalse; for (int i = 0; i < _len; i++) { if (at(i) != rhs.at(i)) { returnfalse;
}
} returntrue;
}
void at_put(int i, const E& elem) {
assert(0 <= i && i < _len, "illegal index");
_data[i] = elem;
}
bool contains(const E& elem) const { for (int i = 0; i < _len; i++) { if (_data[i] == elem) returntrue;
} returnfalse;
}
int find(const E& elem) const { for (int i = 0; i < _len; i++) { if (_data[i] == elem) return i;
} return -1;
}
int find_from_end(const E& elem) const { for (int i = _len-1; i >= 0; i--) { if (_data[i] == elem) return i;
} return -1;
}
int find(void* token, bool f(void*, E)) const { for (int i = 0; i < _len; i++) { if (f(token, _data[i])) return i;
} return -1;
}
int find_from_end(void* token, bool f(void*, E)) const { // start at the end of the array for (int i = _len-1; i >= 0; i--) { if (f(token, _data[i])) return i;
} return -1;
}
// Order preserving remove operations.
void remove(const E& elem) { // Assuming that element does exist. bool removed = remove_if_existing(elem); if (removed) return;
ShouldNotReachHere();
}
bool remove_if_existing(const E& elem) { // Returns TRUE if elem is removed. for (int i = 0; i < _len; i++) { if (_data[i] == elem) {
remove_at(i); returntrue;
}
} returnfalse;
}
void remove_at(int index) {
assert(0 <= index && index < _len, "illegal index"); for (int j = index + 1; j < _len; j++) {
_data[j-1] = _data[j];
}
_len--;
}
// Remove all elements up to the index (exclusive). The order is preserved. void remove_till(int idx) { for (int i = 0, j = idx; j < length(); i++, j++) {
at_put(i, at(j));
}
trunc_to(length() - idx);
}
// The order is changed. void delete_at(int index) {
assert(0 <= index && index < _len, "illegal index"); if (index < --_len) { // Replace removed element with last one.
_data[index] = _data[_len];
}
}
template <typename K, int compare(const K&, const E&)> int find_sorted(const K& key, bool& found) {
found = false; int min = 0; int max = length() - 1;
while (max >= min) { int mid = (int)(((uint)max + min) / 2);
E value = at(mid); int diff = compare(key, value); if (diff > 0) {
min = mid + 1;
} elseif (diff < 0) {
max = mid - 1;
} else {
found = true; return mid;
}
} return min;
}
template <typename K> int find_sorted(CompareClosure<E>* cc, const K& key, bool& found) {
found = false; int min = 0; int max = length() - 1;
while (max >= min) { int mid = (int)(((uint)max + min) / 2);
E value = at(mid); int diff = cc->do_compare(key, value); if (diff > 0) {
min = mid + 1;
} elseif (diff < 0) {
max = mid - 1;
} else {
found = true; return mid;
}
} return min;
}
// GrowableArrayWithAllocator extends the "view" with // the capability to grow and deallocate the data array. // // The allocator responsibility is delegated to the sub-class. // // Derived: The sub-class responsible for allocation / deallocation // - E* Derived::allocate() - member function responsible for allocation // - void Derived::deallocate(E*) - member function responsible for deallocation template <typename E, typename Derived> class GrowableArrayWithAllocator : public GrowableArrayView<E> { friendclass VMStructs;
void expand_to(int j); void grow(int j);
protected:
GrowableArrayWithAllocator(E* data, int capacity) :
GrowableArrayView<E>(data, capacity, 0) { for (int i = 0; i < capacity; i++) {
::new ((void*)&data[i]) E();
}
}
GrowableArrayWithAllocator(E* data, int capacity, int initial_len, const E& filler) :
GrowableArrayView<E>(data, capacity, initial_len) { int i = 0; for (; i < initial_len; i++) {
::new ((void*)&data[i]) E(filler);
} for (; i < capacity; i++) {
::new ((void*)&data[i]) E();
}
}
~GrowableArrayWithAllocator() {}
public: int append(const E& elem) { if (this->_len == this->_capacity) grow(this->_len); int idx = this->_len++;
this->_data[idx] = elem; return idx;
}
bool append_if_missing(const E& elem) { // Returns TRUE if elem is added. bool missed = !this->contains(elem); if (missed) append(elem); return missed;
}
void push(const E& elem) { append(elem); }
E at_grow(int i, const E& fill = E()) {
assert(0 <= i, "negative index"); if (i >= this->_len) { if (i >= this->_capacity) grow(i); for (int j = this->_len; j <= i; j++)
this->_data[j] = fill;
this->_len = i+1;
} return this->_data[i];
}
void at_put_grow(int i, const E& elem, const E& fill = E()) {
assert(0 <= i, "negative index"); if (i >= this->_len) { if (i >= this->_capacity) grow(i); for (int j = this->_len; j < i; j++)
this->_data[j] = fill;
this->_len = i+1;
}
this->_data[i] = elem;
}
// inserts the given element before the element at index i void insert_before(constint idx, const E& elem) {
assert(0 <= idx && idx <= this->_len, "illegal index"); if (this->_len == this->_capacity) grow(this->_len); for (int j = this->_len - 1; j >= idx; j--) {
this->_data[j + 1] = this->_data[j];
}
this->_len++;
this->_data[idx] = elem;
}
void appendAll(const GrowableArrayView<E>* l) { for (int i = 0; i < l->length(); i++) {
this->at_put_grow(this->_len, l->at(i), E());
}
}
// Binary search and insertion utility. Search array for element // matching key according to the static compare function. Insert // that element if not already in the list. Assumes the list is // already sorted according to compare function. template <int compare(const E&, const E&)> E insert_sorted(const E& key) { bool found; int location = GrowableArrayView<E>::template find_sorted<E, compare>(key, found); if (!found) {
insert_before(location, key);
} return this->at(location);
}
E insert_sorted(CompareClosure<E>* cc, const E& key) { bool found; int location = find_sorted(cc, key, found); if (!found) {
insert_before(location, key);
} return this->at(location);
}
// Ensure capacity is at least new_capacity. void reserve(int new_capacity);
// Reduce capacity to length. void shrink_to_fit();
void clear_and_deallocate();
};
template <typename E, typename Derived> void GrowableArrayWithAllocator<E, Derived>::expand_to(int new_capacity) { int old_capacity = this->_capacity;
assert(new_capacity > old_capacity, "expected growth but %d <= %d", new_capacity, old_capacity);
this->_capacity = new_capacity;
E* newData = static_cast<Derived*>(this)->allocate(); int i = 0; for ( ; i < this->_len; i++) ::new ((void*)&newData[i]) E(this->_data[i]); for ( ; i < this->_capacity; i++) ::new ((void*)&newData[i]) E(); for (i = 0; i < old_capacity; i++) this->_data[i].~E(); if (this->_data != NULL) { static_cast<Derived*>(this)->deallocate(this->_data);
}
this->_data = newData;
}
template <typename E, typename Derived> void GrowableArrayWithAllocator<E, Derived>::grow(int j) { // grow the array by increasing _capacity to the first power of two larger than the size we need
expand_to(next_power_of_2((uint32_t)j));
}
template <typename E, typename Derived> void GrowableArrayWithAllocator<E, Derived>::reserve(int new_capacity) { if (new_capacity > this->_capacity) {
expand_to(new_capacity);
}
}
template <typename E, typename Derived> void GrowableArrayWithAllocator<E, Derived>::shrink_to_fit() { int old_capacity = this->_capacity; int len = this->_len;
assert(len <= old_capacity, "invariant");
// If already at full capacity, nothing to do. if (len == old_capacity) { return;
}
// If not empty, allocate new, smaller, data, and copy old data to it.
E* old_data = this->_data;
E* new_data = nullptr;
this->_capacity = len; // Must preceed allocate(). if (len > 0) {
new_data = static_cast<Derived*>(this)->allocate(); for (int i = 0; i < len; ++i) ::new (&new_data[i]) E(old_data[i]);
} // Destroy contents of old data, and deallocate it. for (int i = 0; i < old_capacity; ++i) old_data[i].~E(); if (old_data != nullptr) { static_cast<Derived*>(this)->deallocate(old_data);
} // Install new data, which might be nullptr.
this->_data = new_data;
}
// THE GrowableArray. // // Supports multiple allocation strategies: // - Resource stack allocation: if no extra argument is provided // - CHeap allocation: if memflags is provided // - Arena allocation: if an arena is provided // // There are some drawbacks of using GrowableArray, that are removed in some // of the other implementations of GrowableArrayWithAllocator sub-classes: // // Memory overhead: The multiple allocation strategies uses extra metadata // embedded in the instance. // // Strict allocation locations: There are rules about where the GrowableArray // instance is allocated, that depends on where the data array is allocated. // See: init_checks.
template <typename E> class GrowableArray : public GrowableArrayWithAllocator<E, GrowableArray<E> > { friendclass GrowableArrayWithAllocator<E, GrowableArray<E> >; friendclass GrowableArrayTest;
// Custom STL-style iterator to iterate over GrowableArrays // It is constructed by invoking GrowableArray::begin() and GrowableArray::end() template <typename E> class GrowableArrayIterator : public StackObj { friendclass GrowableArrayView<E>; template <typename F, typename UnaryPredicate> friendclass GrowableArrayFilterIterator;
private: const GrowableArrayView<E>* _array; // GrowableArray we iterate over int _position; // The current position in the GrowableArray
// Private constructor used in GrowableArray::begin() and GrowableArray::end()
GrowableArrayIterator(const GrowableArrayView<E>* array, int position) : _array(array), _position(position) {
assert(0 <= position && position <= _array->length(), "illegal position");
}
booloperator==(const GrowableArrayIterator<E>& rhs) {
assert(_array == rhs._array, "iterator belongs to different array"); return _position == rhs._position;
}
booloperator!=(const GrowableArrayIterator<E>& rhs) {
assert(_array == rhs._array, "iterator belongs to different array"); return _position != rhs._position;
}
};
// Custom STL-style iterator to iterate over elements of a GrowableArray that satisfy a given predicate template <typename E, class UnaryPredicate> class GrowableArrayFilterIterator : public StackObj { friendclass GrowableArrayView<E>;
private: const GrowableArrayView<E>* _array; // GrowableArray we iterate over int _position; // Current position in the GrowableArray
UnaryPredicate _predicate; // Unary predicate the elements of the GrowableArray should satisfy
public:
GrowableArrayFilterIterator(const GrowableArrayIterator<E>& begin, UnaryPredicate filter_predicate) :
_array(begin._array), _position(begin._position), _predicate(filter_predicate) { // Advance to first element satisfying the predicate while(_position != _array->length() && !_predicate(_array->at(_position))) {
++_position;
}
}
GrowableArrayFilterIterator<E, UnaryPredicate>& operator++() { do { // Advance to next element satisfying the predicate
++_position;
} while(_position != _array->length() && !_predicate(_array->at(_position))); return *this;
}
E operator*() { return _array->at(_position); }
booloperator==(const GrowableArrayIterator<E>& rhs) {
assert(_array == rhs._array, "iterator belongs to different array"); return _position == rhs._position;
}
booloperator!=(const GrowableArrayIterator<E>& rhs) {
assert(_array == rhs._array, "iterator belongs to different array"); return _position != rhs._position;
}
booloperator==(const GrowableArrayFilterIterator<E, UnaryPredicate>& rhs) {
assert(_array == rhs._array, "iterator belongs to different array"); return _position == rhs._position;
}
booloperator!=(const GrowableArrayFilterIterator<E, UnaryPredicate>& rhs) {
assert(_array == rhs._array, "iterator belongs to different array"); return _position != rhs._position;
}
};
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.20Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.