mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-17 17:44:40 +02:00
8295808: GrowableArray should support capacity management
Reviewed-by: aboldtch, tschatzl, sspitsyn
This commit is contained in:
parent
6289600fe8
commit
3a873d3c5b
8 changed files with 176 additions and 105 deletions
|
@ -1902,7 +1902,7 @@ void GraphBuilder::check_args_for_profiling(Values* obj_args, int expected) {
|
|||
bool ignored_will_link;
|
||||
ciSignature* declared_signature = NULL;
|
||||
ciMethod* real_target = method()->get_method_at_bci(bci(), ignored_will_link, &declared_signature);
|
||||
assert(expected == obj_args->max_length() || real_target->is_method_handle_intrinsic(), "missed on arg?");
|
||||
assert(expected == obj_args->capacity() || real_target->is_method_handle_intrinsic(), "missed on arg?");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1913,7 +1913,7 @@ Values* GraphBuilder::collect_args_for_profiling(Values* args, ciMethod* target,
|
|||
if (obj_args == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
int s = obj_args->max_length();
|
||||
int s = obj_args->capacity();
|
||||
// if called through method handle invoke, some arguments may have been popped
|
||||
for (int i = start, j = 0; j < s && i < args->length(); i++) {
|
||||
if (args->at(i)->type()->is_object_kind()) {
|
||||
|
@ -3968,9 +3968,9 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, bool ign
|
|||
int start = 0;
|
||||
Values* obj_args = args_list_for_profiling(callee, start, has_receiver);
|
||||
if (obj_args != NULL) {
|
||||
int s = obj_args->max_length();
|
||||
int s = obj_args->capacity();
|
||||
// if called through method handle invoke, some arguments may have been popped
|
||||
for (int i = args_base+start, j = 0; j < obj_args->max_length() && i < state()->stack_size(); ) {
|
||||
for (int i = args_base+start, j = 0; j < obj_args->capacity() && i < state()->stack_size(); ) {
|
||||
Value v = state()->stack_at_inc(i);
|
||||
if (v->type()->is_object_kind()) {
|
||||
obj_args->push(v);
|
||||
|
|
|
@ -56,10 +56,11 @@
|
|||
// the vectors. The size of the table is the size of either vector.
|
||||
//
|
||||
// The capacity of the vectors is explicitly controlled, based on the size.
|
||||
// Given N > 0 and 2^N <= size < 2^(N+1), then capacity = 2^N + k * 2^(N-1)
|
||||
// Given N > 0 and 2^N <= size < 2^(N+1), then capacity <= 2^N + k * 2^(N-1)
|
||||
// for the smallest integer k in [0,2] such that size <= capacity. That is,
|
||||
// use a power of 2 or the midpoint between consecutive powers of 2 that is
|
||||
// minimally at least size.
|
||||
// minimally at least size. When adding an entry and the capacity has been
|
||||
// reached, capacity is increased to the next of those values.
|
||||
//
|
||||
// The main benefit of this representation is that it uses less space than a
|
||||
// more traditional linked-list of entry nodes representation. Such a
|
||||
|
@ -89,12 +90,11 @@ class StringDedup::Table::Bucket {
|
|||
GrowableArrayCHeap<uint, mtStringDedup> _hashes;
|
||||
GrowableArrayCHeap<TableValue, mtStringDedup> _values;
|
||||
|
||||
void adjust_capacity(int new_capacity);
|
||||
void expand_if_full();
|
||||
|
||||
public:
|
||||
// precondition: reserve == 0 or is the result of needed_capacity.
|
||||
Bucket(int reserve = 0);
|
||||
explicit Bucket(int reserve = 0);
|
||||
|
||||
~Bucket() {
|
||||
while (!_values.is_empty()) {
|
||||
|
@ -107,7 +107,7 @@ public:
|
|||
const GrowableArrayView<uint>& hashes() const { return _hashes; }
|
||||
const GrowableArrayView<TableValue>& values() const { return _values; }
|
||||
|
||||
bool is_empty() const { return _hashes.length() == 0; }
|
||||
bool is_empty() const { return _hashes.is_empty(); }
|
||||
int length() const { return _hashes.length(); }
|
||||
|
||||
void add(uint hash_code, TableValue value) {
|
||||
|
@ -150,33 +150,17 @@ int StringDedup::Table::Bucket::needed_capacity(int needed) {
|
|||
return (needed <= low) ? low : high;
|
||||
}
|
||||
|
||||
void StringDedup::Table::Bucket::adjust_capacity(int new_capacity) {
|
||||
GrowableArrayCHeap<uint, mtStringDedup> new_hashes{new_capacity};
|
||||
GrowableArrayCHeap<TableValue, mtStringDedup> new_values{new_capacity};
|
||||
while (!_hashes.is_empty()) {
|
||||
new_hashes.push(_hashes.pop());
|
||||
new_values.push(_values.pop());
|
||||
}
|
||||
_hashes.swap(&new_hashes);
|
||||
_values.swap(&new_values);
|
||||
}
|
||||
|
||||
void StringDedup::Table::Bucket::expand_if_full() {
|
||||
if (_hashes.length() == _hashes.max_length()) {
|
||||
adjust_capacity(needed_capacity(_hashes.max_length() + 1));
|
||||
if (_hashes.is_full()) {
|
||||
int needed = needed_capacity(_hashes.capacity() + 1);
|
||||
_hashes.reserve(needed);
|
||||
_values.reserve(needed);
|
||||
}
|
||||
}
|
||||
|
||||
void StringDedup::Table::Bucket::shrink() {
|
||||
if (_hashes.is_empty()) {
|
||||
_hashes.clear_and_deallocate();
|
||||
_values.clear_and_deallocate();
|
||||
} else {
|
||||
int target = needed_capacity(_hashes.length());
|
||||
if (target < _hashes.max_length()) {
|
||||
adjust_capacity(target);
|
||||
}
|
||||
}
|
||||
_hashes.shrink_to_fit();
|
||||
_values.shrink_to_fit();
|
||||
}
|
||||
|
||||
StringDedup::Table::TableValue
|
||||
|
|
|
@ -256,7 +256,7 @@ static void initialize_dummy_descriptors(GrowableArray<DCmdArgumentInfo*>* array
|
|||
false,
|
||||
true, // a DcmdFramework "option"
|
||||
false);
|
||||
for (int i = 0; i < array->max_length(); ++i) {
|
||||
for (int i = 0; i < array->capacity(); ++i) {
|
||||
array->append(dummy);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -487,7 +487,7 @@
|
|||
/*******************/ \
|
||||
\
|
||||
nonstatic_field(GrowableArrayBase, _len, int) \
|
||||
nonstatic_field(GrowableArrayBase, _max, int) \
|
||||
nonstatic_field(GrowableArrayBase, _capacity, int) \
|
||||
nonstatic_field(GrowableArray<int>, _data, int*) \
|
||||
\
|
||||
/********************************/ \
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
|
@ -76,23 +76,23 @@ protected:
|
|||
// Current number of accessible elements
|
||||
int _len;
|
||||
// Current number of allocated elements
|
||||
int _max;
|
||||
int _capacity;
|
||||
|
||||
GrowableArrayBase(int initial_max, int initial_len) :
|
||||
GrowableArrayBase(int capacity, int initial_len) :
|
||||
_len(initial_len),
|
||||
_max(initial_max) {
|
||||
assert(_len >= 0 && _len <= _max, "initial_len too big");
|
||||
_capacity(capacity) {
|
||||
assert(_len >= 0 && _len <= _capacity, "initial_len too big");
|
||||
}
|
||||
|
||||
~GrowableArrayBase() {}
|
||||
|
||||
public:
|
||||
int length() const { return _len; }
|
||||
int max_length() const { return _max; }
|
||||
int capacity() const { return _capacity; }
|
||||
|
||||
bool is_empty() const { return _len == 0; }
|
||||
bool is_nonempty() const { return _len != 0; }
|
||||
bool is_full() const { return _len == _max; }
|
||||
bool is_full() const { return _len == _capacity; }
|
||||
|
||||
void clear() { _len = 0; }
|
||||
void trunc_to(int length) {
|
||||
|
@ -118,8 +118,8 @@ class GrowableArrayView : public GrowableArrayBase {
|
|||
protected:
|
||||
E* _data; // data array
|
||||
|
||||
GrowableArrayView<E>(E* data, int initial_max, int initial_len) :
|
||||
GrowableArrayBase(initial_max, initial_len), _data(data) {}
|
||||
GrowableArrayView<E>(E* data, int capacity, int initial_len) :
|
||||
GrowableArrayBase(capacity, initial_len), _data(data) {}
|
||||
|
||||
~GrowableArrayView() {}
|
||||
|
||||
|
@ -157,12 +157,12 @@ public:
|
|||
}
|
||||
|
||||
E first() const {
|
||||
assert(_len > 0, "empty list");
|
||||
assert(_len > 0, "empty");
|
||||
return _data[0];
|
||||
}
|
||||
|
||||
E top() const {
|
||||
assert(_len > 0, "empty list");
|
||||
assert(_len > 0, "empty");
|
||||
return _data[_len-1];
|
||||
}
|
||||
|
||||
|
@ -337,7 +337,7 @@ public:
|
|||
|
||||
void print() const {
|
||||
tty->print("Growable Array " PTR_FORMAT, p2i(this));
|
||||
tty->print(": length %d (_max %d) { ", _len, _max);
|
||||
tty->print(": length %d (capacity %d) { ", _len, _capacity);
|
||||
for (int i = 0; i < _len; i++) {
|
||||
tty->print(INTPTR_FORMAT " ", *(intptr_t*)&(_data[i]));
|
||||
}
|
||||
|
@ -360,23 +360,24 @@ 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 initial_max) :
|
||||
GrowableArrayView<E>(data, initial_max, 0) {
|
||||
for (int i = 0; i < initial_max; i++) {
|
||||
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 initial_max, int initial_len, const E& filler) :
|
||||
GrowableArrayView<E>(data, initial_max, initial_len) {
|
||||
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 < initial_max; i++) {
|
||||
for (; i < capacity; i++) {
|
||||
::new ((void*)&data[i]) E();
|
||||
}
|
||||
}
|
||||
|
@ -385,7 +386,7 @@ protected:
|
|||
|
||||
public:
|
||||
int append(const E& elem) {
|
||||
if (this->_len == this->_max) grow(this->_len);
|
||||
if (this->_len == this->_capacity) grow(this->_len);
|
||||
int idx = this->_len++;
|
||||
this->_data[idx] = elem;
|
||||
return idx;
|
||||
|
@ -403,7 +404,7 @@ public:
|
|||
E at_grow(int i, const E& fill = E()) {
|
||||
assert(0 <= i, "negative index");
|
||||
if (i >= this->_len) {
|
||||
if (i >= this->_max) grow(i);
|
||||
if (i >= this->_capacity) grow(i);
|
||||
for (int j = this->_len; j <= i; j++)
|
||||
this->_data[j] = fill;
|
||||
this->_len = i+1;
|
||||
|
@ -414,7 +415,7 @@ public:
|
|||
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->_max) grow(i);
|
||||
if (i >= this->_capacity) grow(i);
|
||||
for (int j = this->_len; j < i; j++)
|
||||
this->_data[j] = fill;
|
||||
this->_len = i+1;
|
||||
|
@ -425,7 +426,7 @@ public:
|
|||
// 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->_max) grow(this->_len);
|
||||
if (this->_len == this->_capacity) grow(this->_len);
|
||||
for (int j = this->_len - 1; j >= idx; j--) {
|
||||
this->_data[j + 1] = this->_data[j];
|
||||
}
|
||||
|
@ -437,7 +438,7 @@ public:
|
|||
assert(0 <= idx && idx <= this->_len, "illegal index");
|
||||
int array_len = array->length();
|
||||
int new_len = this->_len + array_len;
|
||||
if (new_len >= this->_max) grow(new_len);
|
||||
if (new_len >= this->_capacity) grow(new_len);
|
||||
|
||||
for (int j = this->_len - 1; j >= idx; j--) {
|
||||
this->_data[j + array_len] = this->_data[j];
|
||||
|
@ -481,40 +482,80 @@ public:
|
|||
void swap(GrowableArrayWithAllocator<E, Derived>* other) {
|
||||
::swap(this->_data, other->_data);
|
||||
::swap(this->_len, other->_len);
|
||||
::swap(this->_max, other->_max);
|
||||
::swap(this->_capacity, other->_capacity);
|
||||
}
|
||||
|
||||
// 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>::grow(int j) {
|
||||
int old_max = this->_max;
|
||||
// grow the array by increasing _max to the first power of two larger than the size we need
|
||||
this->_max = next_power_of_2((uint32_t)j);
|
||||
// j < _max
|
||||
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->_max; i++) ::new ((void*)&newData[i]) E();
|
||||
for (i = 0; i < old_max; i++) this->_data[i].~E();
|
||||
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;
|
||||
}
|
||||
|
||||
template <typename E, typename Derived>
|
||||
void GrowableArrayWithAllocator<E, Derived>::clear_and_deallocate() {
|
||||
if (this->_data != NULL) {
|
||||
for (int i = 0; i < this->_max; i++) {
|
||||
this->_data[i].~E();
|
||||
}
|
||||
static_cast<Derived*>(this)->deallocate(this->_data);
|
||||
this->_data = NULL;
|
||||
}
|
||||
this->_len = 0;
|
||||
this->_max = 0;
|
||||
this->clear();
|
||||
this->shrink_to_fit();
|
||||
}
|
||||
|
||||
class GrowableArrayResourceAllocator {
|
||||
|
@ -661,15 +702,15 @@ class GrowableArray : public GrowableArrayWithAllocator<E, GrowableArray<E> > {
|
|||
E* allocate() {
|
||||
if (on_stack()) {
|
||||
debug_only(_metadata.on_stack_alloc_check());
|
||||
return allocate(this->_max);
|
||||
return allocate(this->_capacity);
|
||||
}
|
||||
|
||||
if (on_C_heap()) {
|
||||
return allocate(this->_max, _metadata.memflags());
|
||||
return allocate(this->_capacity, _metadata.memflags());
|
||||
}
|
||||
|
||||
assert(on_arena(), "Sanity");
|
||||
return allocate(this->_max, _metadata.arena());
|
||||
return allocate(this->_capacity, _metadata.arena());
|
||||
}
|
||||
|
||||
void deallocate(E* mem) {
|
||||
|
@ -679,26 +720,26 @@ class GrowableArray : public GrowableArrayWithAllocator<E, GrowableArray<E> > {
|
|||
}
|
||||
|
||||
public:
|
||||
GrowableArray(int initial_max = 2, MEMFLAGS memflags = mtNone) :
|
||||
GrowableArray(int initial_capacity = 2, MEMFLAGS memflags = mtNone) :
|
||||
GrowableArrayWithAllocator<E, GrowableArray<E> >(
|
||||
allocate(initial_max, memflags),
|
||||
initial_max),
|
||||
allocate(initial_capacity, memflags),
|
||||
initial_capacity),
|
||||
_metadata(memflags) {
|
||||
init_checks();
|
||||
}
|
||||
|
||||
GrowableArray(int initial_max, int initial_len, const E& filler, MEMFLAGS memflags = mtNone) :
|
||||
GrowableArray(int initial_capacity, int initial_len, const E& filler, MEMFLAGS memflags = mtNone) :
|
||||
GrowableArrayWithAllocator<E, GrowableArray<E> >(
|
||||
allocate(initial_max, memflags),
|
||||
initial_max, initial_len, filler),
|
||||
allocate(initial_capacity, memflags),
|
||||
initial_capacity, initial_len, filler),
|
||||
_metadata(memflags) {
|
||||
init_checks();
|
||||
}
|
||||
|
||||
GrowableArray(Arena* arena, int initial_max, int initial_len, const E& filler) :
|
||||
GrowableArray(Arena* arena, int initial_capacity, int initial_len, const E& filler) :
|
||||
GrowableArrayWithAllocator<E, GrowableArray<E> >(
|
||||
allocate(initial_max, arena),
|
||||
initial_max, initial_len, filler),
|
||||
allocate(initial_capacity, arena),
|
||||
initial_capacity, initial_len, filler),
|
||||
_metadata(arena) {
|
||||
init_checks();
|
||||
}
|
||||
|
@ -728,7 +769,7 @@ class GrowableArrayCHeap : public GrowableArrayWithAllocator<E, GrowableArrayCHe
|
|||
NONCOPYABLE(GrowableArrayCHeap);
|
||||
|
||||
E* allocate() {
|
||||
return allocate(this->_max, F);
|
||||
return allocate(this->_capacity, F);
|
||||
}
|
||||
|
||||
void deallocate(E* mem) {
|
||||
|
@ -736,15 +777,15 @@ class GrowableArrayCHeap : public GrowableArrayWithAllocator<E, GrowableArrayCHe
|
|||
}
|
||||
|
||||
public:
|
||||
GrowableArrayCHeap(int initial_max = 0) :
|
||||
GrowableArrayCHeap(int initial_capacity = 0) :
|
||||
GrowableArrayWithAllocator<E, GrowableArrayCHeap<E, F> >(
|
||||
allocate(initial_max, F),
|
||||
initial_max) {}
|
||||
allocate(initial_capacity, F),
|
||||
initial_capacity) {}
|
||||
|
||||
GrowableArrayCHeap(int initial_max, int initial_len, const E& filler) :
|
||||
GrowableArrayCHeap(int initial_capacity, int initial_len, const E& filler) :
|
||||
GrowableArrayWithAllocator<E, GrowableArrayCHeap<E, F> >(
|
||||
allocate(initial_max, F),
|
||||
initial_max, initial_len, filler) {}
|
||||
allocate(initial_capacity, F),
|
||||
initial_capacity, initial_len, filler) {}
|
||||
|
||||
~GrowableArrayCHeap() {
|
||||
this->clear_and_deallocate();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 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
|
||||
|
@ -43,15 +43,15 @@ public class GenericGrowableArray extends VMObject {
|
|||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("GrowableArrayBase");
|
||||
_max_field = new CIntField(type.getCIntegerField("_max"), 0);
|
||||
_capacity_field = new CIntField(type.getCIntegerField("_capacity"), 0);
|
||||
_len_field = new CIntField(type.getCIntegerField("_len"), 0);
|
||||
}
|
||||
|
||||
private static CIntField _max_field;
|
||||
private static CIntField _capacity_field;
|
||||
private static CIntField _len_field;
|
||||
|
||||
public int max() {
|
||||
return (int)_max_field.getValue(getAddress());
|
||||
public int capacity() {
|
||||
return (int)_capacity_field.getValue(getAddress());
|
||||
}
|
||||
|
||||
public int length() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 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
|
||||
|
@ -39,11 +39,11 @@ TEST(ZArray, sanity) {
|
|||
|
||||
// Check size
|
||||
ASSERT_EQ(a.length(), 0);
|
||||
ASSERT_EQ(a.max_length(), 0);
|
||||
ASSERT_EQ(a.capacity(), 0);
|
||||
ASSERT_EQ(a.is_empty(), true);
|
||||
|
||||
ASSERT_EQ(b.length(), 10);
|
||||
ASSERT_GE(b.max_length(), 10);
|
||||
ASSERT_GE(b.capacity(), 10);
|
||||
ASSERT_EQ(b.is_empty(), false);
|
||||
|
||||
// Clear elements
|
||||
|
@ -51,14 +51,14 @@ TEST(ZArray, sanity) {
|
|||
|
||||
// Check that b is unaffected
|
||||
ASSERT_EQ(b.length(), 10);
|
||||
ASSERT_GE(b.max_length(), 10);
|
||||
ASSERT_GE(b.capacity(), 10);
|
||||
ASSERT_EQ(b.is_empty(), false);
|
||||
|
||||
a.append(1);
|
||||
|
||||
// Check that b is unaffected
|
||||
ASSERT_EQ(b.length(), 10);
|
||||
ASSERT_GE(b.max_length(), 10);
|
||||
ASSERT_GE(b.capacity(), 10);
|
||||
ASSERT_EQ(b.is_empty(), false);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 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
|
||||
|
@ -124,6 +124,43 @@ protected:
|
|||
ASSERT_EQ(counter, 10);
|
||||
}
|
||||
|
||||
template <typename ArrayClass>
|
||||
static void test_capacity(ArrayClass* a) {
|
||||
ASSERT_EQ(a->length(), 0);
|
||||
a->reserve(50);
|
||||
ASSERT_EQ(a->length(), 0);
|
||||
ASSERT_EQ(a->capacity(), 50);
|
||||
for (int i = 0; i < 50; ++i) {
|
||||
a->append(i);
|
||||
}
|
||||
ASSERT_EQ(a->length(), 50);
|
||||
ASSERT_EQ(a->capacity(), 50);
|
||||
a->append(50);
|
||||
ASSERT_EQ(a->length(), 51);
|
||||
int capacity = a->capacity();
|
||||
ASSERT_GE(capacity, 51);
|
||||
for (int i = 0; i < 30; ++i) {
|
||||
a->pop();
|
||||
}
|
||||
ASSERT_EQ(a->length(), 21);
|
||||
ASSERT_EQ(a->capacity(), capacity);
|
||||
a->shrink_to_fit();
|
||||
ASSERT_EQ(a->length(), 21);
|
||||
ASSERT_EQ(a->capacity(), 21);
|
||||
|
||||
a->reserve(50);
|
||||
ASSERT_EQ(a->length(), 21);
|
||||
ASSERT_EQ(a->capacity(), 50);
|
||||
|
||||
a->clear();
|
||||
ASSERT_EQ(a->length(), 0);
|
||||
ASSERT_EQ(a->capacity(), 50);
|
||||
|
||||
a->shrink_to_fit();
|
||||
ASSERT_EQ(a->length(), 0);
|
||||
ASSERT_EQ(a->capacity(), 0);
|
||||
}
|
||||
|
||||
template <typename ArrayClass>
|
||||
static void test_copy1(ArrayClass* a) {
|
||||
ASSERT_EQ(a->length(), 1);
|
||||
|
@ -200,7 +237,8 @@ protected:
|
|||
enum TestEnum {
|
||||
Append,
|
||||
Clear,
|
||||
Iterator,
|
||||
Capacity,
|
||||
Iterator
|
||||
};
|
||||
|
||||
template <typename ArrayClass>
|
||||
|
@ -214,6 +252,10 @@ protected:
|
|||
test_clear(a);
|
||||
break;
|
||||
|
||||
case Capacity:
|
||||
test_capacity(a);
|
||||
break;
|
||||
|
||||
case Iterator:
|
||||
test_iterator(a);
|
||||
break;
|
||||
|
@ -402,6 +444,10 @@ TEST_VM_F(GrowableArrayTest, clear) {
|
|||
with_all_types_all_0(Clear);
|
||||
}
|
||||
|
||||
TEST_VM_F(GrowableArrayTest, capacity) {
|
||||
with_all_types_all_0(Capacity);
|
||||
}
|
||||
|
||||
TEST_VM_F(GrowableArrayTest, iterator) {
|
||||
with_all_types_all_0(Iterator);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue