/*************************************************************************/ /* */ /* 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 {
friend class 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) return false;
for (int i = 0; i < _len; i++) {
if (at(i) != rhs.at(i)) { return false;
}
} 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;
} return false;
}
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;
}
} return false;
}
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;
} else if (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;
} else if (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> {
friend class 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;
} returnthis->_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(const int 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 insert_before(const int idx, const GrowableArrayView<E>* array) {
assert(0 <= idx && idx <= this->_len, "illegal index");
int array_len = array->length();
int new_len = this->_len + array_len;
if (new_len >= this->_capacity) grow(new_len);
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);
} returnthis->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);
} returnthis->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> > {
friend class GrowableArrayWithAllocator<E, GrowableArray<E> >;
friend class GrowableArrayTest;
~GrowableArray() {
if (on_C_heap()) { this->clear_and_deallocate();
}
}
};
// Leaner GrowableArray for CHeap backed data arrays, with compile-time decided MEMFLAGS. template <typename E, MEMFLAGS F> class GrowableArrayCHeap : public GrowableArrayWithAllocator<E, GrowableArrayCHeap<E, F> > {
friend class GrowableArrayWithAllocator<E, GrowableArrayCHeap<E, F> >;
// 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 {
friend class GrowableArrayView<E>; template <typename F, typename UnaryPredicate> friend class 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 {
friend class 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.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.